first commit
This commit is contained in:
69
fys-system/src/main/java/com/fuyuanshen/AppRun.java
Normal file
69
fys-system/src/main/java/com/fuyuanshen/AppRun.java
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen;
|
||||
|
||||
import io.swagger.annotations.Api;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.fuyuanshen.annotation.rest.AnonymousGetMapping;
|
||||
import com.fuyuanshen.utils.SpringBeanHolder;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.context.ApplicationPidFileWriter;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2018/11/15 9:20:19
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@Api(hidden = true)
|
||||
@SpringBootApplication
|
||||
@EnableTransactionManagement
|
||||
public class AppRun {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication springApplication = new SpringApplication(AppRun.class);
|
||||
// 监控应用的PID,启动时可指定PID路径:--spring.pid.file=/home/eladmin/app.pid
|
||||
// 或者在 application.yml 添加文件路径,方便 kill,kill `cat /home/eladmin/app.pid`
|
||||
springApplication.addListeners(new ApplicationPidFileWriter());
|
||||
springApplication.run(args);
|
||||
log.info("---------------------------------------------");
|
||||
log.info("Local: {}", "http://localhost:8000");
|
||||
log.info("Swagger: {}", "http://localhost:8000/doc.html");
|
||||
log.info("---------------------------------------------");
|
||||
log.info("---test---");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SpringBeanHolder springContextHolder() {
|
||||
return new SpringBeanHolder();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 访问首页提示
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
@AnonymousGetMapping("/")
|
||||
public String index() {
|
||||
return "Backend service started successfully";
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.domain;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.bean.copier.CopyOptions;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import com.fuyuanshen.base.BaseEntity;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("mnt_app")
|
||||
public class App extends BaseEntity implements Serializable {
|
||||
|
||||
|
||||
@TableId(value = "app_id", type = IdType.AUTO)
|
||||
@ApiModelProperty(value = "ID", hidden = true)
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty(value = "名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(value = "端口")
|
||||
private int port;
|
||||
|
||||
@ApiModelProperty(value = "上传路径")
|
||||
private String uploadPath;
|
||||
|
||||
@ApiModelProperty(value = "部署路径")
|
||||
private String deployPath;
|
||||
|
||||
@ApiModelProperty(value = "备份路径")
|
||||
private String backupPath;
|
||||
|
||||
@ApiModelProperty(value = "启动脚本")
|
||||
private String startScript;
|
||||
|
||||
@ApiModelProperty(value = "部署脚本")
|
||||
private String deployScript;
|
||||
|
||||
public void copy(App source){
|
||||
BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.domain;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.bean.copier.CopyOptions;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import com.fuyuanshen.base.BaseEntity;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("mnt_database")
|
||||
public class Database extends BaseEntity implements Serializable {
|
||||
|
||||
@TableId(value = "db_id", type = IdType.AUTO)
|
||||
@ApiModelProperty(value = "ID", hidden = true)
|
||||
private String id;
|
||||
|
||||
@ApiModelProperty(value = "数据库名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(value = "数据库连接地址")
|
||||
private String jdbcUrl;
|
||||
|
||||
@ApiModelProperty(value = "数据库密码")
|
||||
private String pwd;
|
||||
|
||||
@ApiModelProperty(value = "用户名")
|
||||
private String userName;
|
||||
|
||||
public void copy(Database source){
|
||||
BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.domain;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.bean.copier.CopyOptions;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import com.fuyuanshen.base.BaseEntity;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("mnt_deploy")
|
||||
public class Deploy extends BaseEntity implements Serializable {
|
||||
|
||||
@TableId(value = "deploy_id", type = IdType.AUTO)
|
||||
@ApiModelProperty(value = "ID", hidden = true)
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty(value = "应用编号")
|
||||
private Long appId;
|
||||
|
||||
@TableField(exist = false)
|
||||
@ApiModelProperty(name = "服务器", hidden = true)
|
||||
private Set<Server> deploys;
|
||||
|
||||
@TableField(exist = false)
|
||||
@ApiModelProperty(value = "应用")
|
||||
private App app;
|
||||
|
||||
public void copy(Deploy source){
|
||||
BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
|
||||
}
|
||||
|
||||
public String getServers() {
|
||||
if(CollectionUtil.isNotEmpty(deploys)){
|
||||
return deploys.stream().map(Server::getName).collect(Collectors.joining(","));
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.domain;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.bean.copier.CopyOptions;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.Timestamp;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("mnt_deploy_history")
|
||||
public class DeployHistory implements Serializable {
|
||||
|
||||
@TableId(value = "history_id", type = IdType.AUTO)
|
||||
@ApiModelProperty(value = "ID", hidden = true)
|
||||
private String id;
|
||||
|
||||
@ApiModelProperty(value = "应用名称")
|
||||
private String appName;
|
||||
|
||||
@ApiModelProperty(value = "IP")
|
||||
private String ip;
|
||||
|
||||
@ApiModelProperty(value = "部署时间")
|
||||
private Timestamp deployDate;
|
||||
|
||||
@ApiModelProperty(value = "部署者")
|
||||
private String deployUser;
|
||||
|
||||
@ApiModelProperty(value = "部署ID")
|
||||
private Long deployId;
|
||||
|
||||
public void copy(DeployHistory source){
|
||||
BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.domain;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.bean.copier.CopyOptions;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import com.fuyuanshen.base.BaseEntity;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("mnt_server")
|
||||
public class Server extends BaseEntity implements Serializable {
|
||||
|
||||
@TableId(value = "server_id", type = IdType.AUTO)
|
||||
@ApiModelProperty(value = "ID", hidden = true)
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty(value = "服务器名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(value = "IP")
|
||||
private String ip;
|
||||
|
||||
@ApiModelProperty(value = "端口")
|
||||
private Integer port;
|
||||
|
||||
@ApiModelProperty(value = "账号")
|
||||
private String account;
|
||||
|
||||
@ApiModelProperty(value = "密码")
|
||||
private String password;
|
||||
|
||||
public void copy(Server source){
|
||||
BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Server that = (Server) o;
|
||||
return Objects.equals(id, that.id) &&
|
||||
Objects.equals(name, that.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, name);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.domain.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@Data
|
||||
public class AppQueryCriteria{
|
||||
|
||||
@ApiModelProperty(value = "名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(value = "创建时间")
|
||||
private List<Timestamp> createTime;
|
||||
|
||||
@ApiModelProperty(value = "页码", example = "1")
|
||||
private Integer page = 1;
|
||||
|
||||
@ApiModelProperty(value = "每页数据量", example = "10")
|
||||
private Integer size = 10;
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.domain.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@Data
|
||||
public class DatabaseQueryCriteria{
|
||||
|
||||
@ApiModelProperty(value = "名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(value = "数据源")
|
||||
private String jdbcUrl;
|
||||
|
||||
@ApiModelProperty(value = "创建时间")
|
||||
private List<Timestamp> createTime;
|
||||
|
||||
@ApiModelProperty(value = "页码", example = "1")
|
||||
private Integer page = 1;
|
||||
|
||||
@ApiModelProperty(value = "每页数据量", example = "10")
|
||||
private Integer size = 10;
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.domain.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@Data
|
||||
public class DeployHistoryQueryCriteria{
|
||||
|
||||
@ApiModelProperty(value = "模糊查询")
|
||||
private String blurry;
|
||||
|
||||
@ApiModelProperty(value = "部署ID")
|
||||
private Long deployId;
|
||||
|
||||
@ApiModelProperty(value = "部署时间")
|
||||
private List<Timestamp> deployDate;
|
||||
|
||||
@ApiModelProperty(value = "页码", example = "1")
|
||||
private Integer page = 1;
|
||||
|
||||
@ApiModelProperty(value = "每页数据量", example = "10")
|
||||
private Integer size = 10;
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.domain.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@Data
|
||||
public class DeployQueryCriteria{
|
||||
|
||||
@ApiModelProperty(value = "应用名称")
|
||||
private String appName;
|
||||
|
||||
@ApiModelProperty(value = "创建时间")
|
||||
private List<Timestamp> createTime;
|
||||
|
||||
@ApiModelProperty(value = "页码", example = "1")
|
||||
private Integer page = 1;
|
||||
|
||||
@ApiModelProperty(value = "每页数据量", example = "10")
|
||||
private Integer size = 10;
|
||||
|
||||
@ApiModelProperty(value = "查询分页偏移量", hidden = true)
|
||||
private Long offset;
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.domain.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@Data
|
||||
public class ServerQueryCriteria {
|
||||
|
||||
@ApiModelProperty(value = "模糊查询")
|
||||
private String blurry;
|
||||
|
||||
@ApiModelProperty(value = "创建时间")
|
||||
private List<Timestamp> createTime;
|
||||
|
||||
@ApiModelProperty(value = "页码", example = "1")
|
||||
private Integer page = 1;
|
||||
|
||||
@ApiModelProperty(value = "每页数据量", example = "10")
|
||||
private Integer size = 10;
|
||||
}
|
||||
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* <<
|
||||
* Davinci
|
||||
* ==
|
||||
* Copyright (C) 2016 - 2019 EDP
|
||||
* ==
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* >>
|
||||
*
|
||||
*/
|
||||
|
||||
package com.fuyuanshen.modules.maint.domain.enums;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @author /
|
||||
*/
|
||||
@Slf4j
|
||||
@SuppressWarnings({"unchecked","all"})
|
||||
public enum DataTypeEnum {
|
||||
|
||||
/** mysql */
|
||||
MYSQL("mysql", "mysql", "com.mysql.jdbc.Driver", "`", "`", "'", "'"),
|
||||
|
||||
/** oracle */
|
||||
ORACLE("oracle", "oracle", "oracle.jdbc.driver.OracleDriver", "\"", "\"", "\"", "\""),
|
||||
|
||||
/** sql server */
|
||||
SQLSERVER("sqlserver", "sqlserver", "com.microsoft.sqlserver.jdbc.SQLServerDriver", "\"", "\"", "\"", "\""),
|
||||
|
||||
/** h2 */
|
||||
H2("h2", "h2", "org.h2.Driver", "`", "`", "\"", "\""),
|
||||
|
||||
/** phoenix */
|
||||
PHOENIX("phoenix", "hbase phoenix", "org.apache.phoenix.jdbc.PhoenixDriver", "", "", "\"", "\""),
|
||||
|
||||
/** mongo */
|
||||
MONGODB("mongo", "mongodb", "mongodb.jdbc.MongoDriver", "`", "`", "\"", "\""),
|
||||
|
||||
/** sql4es */
|
||||
ELASTICSEARCH("sql4es", "elasticsearch", "nl.anchormen.sql4es.jdbc.ESDriver", "", "", "'", "'"),
|
||||
|
||||
/** presto */
|
||||
PRESTO("presto", "presto", "com.facebook.presto.jdbc.PrestoDriver", "", "", "\"", "\""),
|
||||
|
||||
/** moonbox */
|
||||
MOONBOX("moonbox", "moonbox", "moonbox.jdbc.MbDriver", "`", "`", "`", "`"),
|
||||
|
||||
/** cassandra */
|
||||
CASSANDRA("cassandra", "cassandra", "com.github.adejanovski.cassandra.jdbc.CassandraDriver", "", "", "'", "'"),
|
||||
|
||||
/** click house */
|
||||
CLICKHOUSE("clickhouse", "clickhouse", "ru.yandex.clickhouse.ClickHouseDriver", "", "", "\"", "\""),
|
||||
|
||||
/** kylin */
|
||||
KYLIN("kylin", "kylin", "org.apache.kylin.jdbc.Driver", "\"", "\"", "\"", "\""),
|
||||
|
||||
/** vertica */
|
||||
VERTICA("vertica", "vertica", "com.vertica.jdbc.Driver", "", "", "'", "'"),
|
||||
|
||||
/** sap */
|
||||
HANA("sap", "sap hana", "com.sap.db.jdbc.Driver", "", "", "'", "'"),
|
||||
|
||||
/** impala */
|
||||
IMPALA("impala", "impala", "com.cloudera.impala.jdbc41.Driver", "", "", "'", "'");
|
||||
|
||||
private String feature;
|
||||
private String desc;
|
||||
private String driver;
|
||||
private String keywordPrefix;
|
||||
private String keywordSuffix;
|
||||
private String aliasPrefix;
|
||||
private String aliasSuffix;
|
||||
|
||||
private static final String JDBC_URL_PREFIX = "jdbc:";
|
||||
|
||||
DataTypeEnum(String feature, String desc, String driver, String keywordPrefix, String keywordSuffix, String aliasPrefix, String aliasSuffix) {
|
||||
this.feature = feature;
|
||||
this.desc = desc;
|
||||
this.driver = driver;
|
||||
this.keywordPrefix = keywordPrefix;
|
||||
this.keywordSuffix = keywordSuffix;
|
||||
this.aliasPrefix = aliasPrefix;
|
||||
this.aliasSuffix = aliasSuffix;
|
||||
}
|
||||
|
||||
public static DataTypeEnum urlOf(String jdbcUrl) {
|
||||
String url = jdbcUrl.toLowerCase().trim();
|
||||
for (DataTypeEnum dataTypeEnum : values()) {
|
||||
if (url.startsWith(JDBC_URL_PREFIX + dataTypeEnum.feature)) {
|
||||
try {
|
||||
Class<?> aClass = Class.forName(dataTypeEnum.getDriver());
|
||||
if (null == aClass) {
|
||||
throw new RuntimeException("Unable to get driver instance for jdbcUrl: " + jdbcUrl);
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException("Unable to get driver instance: " + jdbcUrl);
|
||||
}
|
||||
return dataTypeEnum;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getFeature() {
|
||||
return feature;
|
||||
}
|
||||
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
public String getDriver() {
|
||||
return driver;
|
||||
}
|
||||
|
||||
public String getKeywordPrefix() {
|
||||
return keywordPrefix;
|
||||
}
|
||||
|
||||
public String getKeywordSuffix() {
|
||||
return keywordSuffix;
|
||||
}
|
||||
|
||||
public String getAliasPrefix() {
|
||||
return aliasPrefix;
|
||||
}
|
||||
|
||||
public String getAliasSuffix() {
|
||||
return aliasSuffix;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.domain.enums;
|
||||
|
||||
/**
|
||||
* @author ZhangHouYing
|
||||
* @date 2019-08-10 9:56
|
||||
*/
|
||||
public enum MsgType {
|
||||
/** 连接 */
|
||||
CONNECT,
|
||||
/** 关闭 */
|
||||
CLOSE,
|
||||
/** 信息 */
|
||||
INFO,
|
||||
/** 错误 */
|
||||
ERROR
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2019-2023 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.fuyuanshen.modules.maint.domain.App;
|
||||
import com.fuyuanshen.modules.maint.domain.dto.AppQueryCriteria;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @description
|
||||
* @date 2023-06-12
|
||||
**/
|
||||
@Mapper
|
||||
public interface AppMapper extends BaseMapper<App> {
|
||||
|
||||
IPage<App> queryAll(@Param("criteria") AppQueryCriteria criteria, Page<Object> page);
|
||||
|
||||
List<App> queryAll(@Param("criteria") AppQueryCriteria criteria);
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2019-2023 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.fuyuanshen.modules.maint.domain.Database;
|
||||
import com.fuyuanshen.modules.maint.domain.dto.DatabaseQueryCriteria;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @description
|
||||
* @date 2023-06-12
|
||||
**/
|
||||
@Mapper
|
||||
public interface DatabaseMapper extends BaseMapper<Database> {
|
||||
|
||||
IPage<Database> findAll(@Param("criteria") DatabaseQueryCriteria criteria, Page<Object> page);
|
||||
|
||||
List<Database> findAll(@Param("criteria") DatabaseQueryCriteria criteria);
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2019-2023 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.fuyuanshen.modules.maint.domain.DeployHistory;
|
||||
import com.fuyuanshen.modules.maint.domain.dto.DeployHistoryQueryCriteria;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @description
|
||||
* @date 2023-06-12
|
||||
**/
|
||||
@Mapper
|
||||
public interface DeployHistoryMapper extends BaseMapper<DeployHistory> {
|
||||
|
||||
IPage<DeployHistory> findAll(@Param("criteria") DeployHistoryQueryCriteria criteria, Page<Object> page);
|
||||
|
||||
List<DeployHistory> findAll(@Param("criteria") DeployHistoryQueryCriteria criteria);
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2019-2023 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.fuyuanshen.modules.maint.domain.Deploy;
|
||||
import com.fuyuanshen.modules.maint.domain.dto.DeployQueryCriteria;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @description
|
||||
* @date 2023-06-12
|
||||
**/
|
||||
@Mapper
|
||||
public interface DeployMapper extends BaseMapper<Deploy> {
|
||||
|
||||
Long countAll(@Param("criteria") DeployQueryCriteria criteria);
|
||||
|
||||
List<Deploy> findAll(@Param("criteria") DeployQueryCriteria criteria);
|
||||
|
||||
Set<Long> getIdByAppIds(@Param("appIds") Set<Long> appIds);
|
||||
|
||||
Deploy getDeployById(@Param("deployId") Long deployId);
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2019-2023 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.mapper;
|
||||
|
||||
import com.fuyuanshen.modules.maint.domain.Server;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @description
|
||||
* @date 2023-06-12
|
||||
**/
|
||||
@Mapper
|
||||
public interface DeployServerMapper {
|
||||
|
||||
void insertData(@Param("deployId") Long deployId, @Param("servers") Set<Server> servers);
|
||||
|
||||
void deleteByDeployId(@Param("deployId") Long deployId);
|
||||
|
||||
void deleteByDeployIds(@Param("deployIds") Set<Long> deployIds);
|
||||
|
||||
void deleteByServerIds(@Param("serverIds") Set<Long> serverIds);
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2019-2023 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.fuyuanshen.modules.maint.domain.Server;
|
||||
import com.fuyuanshen.modules.maint.domain.dto.ServerQueryCriteria;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @description
|
||||
* @date 2023-06-12
|
||||
**/
|
||||
@Mapper
|
||||
public interface ServerMapper extends BaseMapper<Server> {
|
||||
Server findByIp(@Param("ip") String ip);
|
||||
|
||||
IPage<Server> findAll(@Param("criteria") ServerQueryCriteria criteria, Page<Object> page);
|
||||
|
||||
List<Server> findAll(@Param("criteria") ServerQueryCriteria criteria);
|
||||
}
|
||||
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.rest;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import com.fuyuanshen.annotation.Log;
|
||||
import com.fuyuanshen.modules.maint.domain.App;
|
||||
import com.fuyuanshen.modules.maint.domain.dto.AppQueryCriteria;
|
||||
import com.fuyuanshen.modules.maint.service.AppService;
|
||||
import com.fuyuanshen.utils.PageResult;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@Api(tags = "运维:应用管理")
|
||||
@RequestMapping("/api/app")
|
||||
public class AppController {
|
||||
|
||||
private final AppService appService;
|
||||
|
||||
@ApiOperation("导出应用数据")
|
||||
@GetMapping(value = "/download")
|
||||
@PreAuthorize("@el.check('app:list')")
|
||||
public void exportApp(HttpServletResponse response, AppQueryCriteria criteria) throws IOException {
|
||||
appService.download(appService.queryAll(criteria), response);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "查询应用")
|
||||
@GetMapping
|
||||
@PreAuthorize("@el.check('app:list')")
|
||||
public ResponseEntity<PageResult<App>> queryApp(AppQueryCriteria criteria){
|
||||
Page<Object> page = new Page<>(criteria.getPage(), criteria.getSize());
|
||||
return new ResponseEntity<>(appService.queryAll(criteria, page),HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Log("新增应用")
|
||||
@ApiOperation(value = "新增应用")
|
||||
@PostMapping
|
||||
@PreAuthorize("@el.check('app:add')")
|
||||
public ResponseEntity<Object> createApp(@Validated @RequestBody App resources){
|
||||
appService.create(resources);
|
||||
return new ResponseEntity<>(HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@Log("修改应用")
|
||||
@ApiOperation(value = "修改应用")
|
||||
@PutMapping
|
||||
@PreAuthorize("@el.check('app:edit')")
|
||||
public ResponseEntity<Object> updateApp(@Validated @RequestBody App resources){
|
||||
appService.update(resources);
|
||||
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
@Log("删除应用")
|
||||
@ApiOperation(value = "删除应用")
|
||||
@DeleteMapping
|
||||
@PreAuthorize("@el.check('app:del')")
|
||||
public ResponseEntity<Object> deleteApp(@RequestBody Set<Long> ids){
|
||||
appService.delete(ids);
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.rest;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import com.fuyuanshen.annotation.Log;
|
||||
import com.fuyuanshen.exception.BadRequestException;
|
||||
import com.fuyuanshen.modules.maint.domain.Database;
|
||||
import com.fuyuanshen.modules.maint.domain.dto.DatabaseQueryCriteria;
|
||||
import com.fuyuanshen.modules.maint.service.DatabaseService;
|
||||
import com.fuyuanshen.modules.maint.util.SqlUtils;
|
||||
import com.fuyuanshen.utils.FileUtil;
|
||||
import com.fuyuanshen.utils.PageResult;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@Api(tags = "运维:数据库管理")
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/api/database")
|
||||
public class DatabaseController {
|
||||
|
||||
private final String fileSavePath = FileUtil.getTmpDirPath()+"/";
|
||||
private final DatabaseService databaseService;
|
||||
|
||||
@ApiOperation("导出数据库数据")
|
||||
@GetMapping(value = "/download")
|
||||
@PreAuthorize("@el.check('database:list')")
|
||||
public void exportDatabase(HttpServletResponse response, DatabaseQueryCriteria criteria) throws IOException {
|
||||
databaseService.download(databaseService.queryAll(criteria), response);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "查询数据库")
|
||||
@GetMapping
|
||||
@PreAuthorize("@el.check('database:list')")
|
||||
public ResponseEntity<PageResult<Database>> queryDatabase(DatabaseQueryCriteria criteria){
|
||||
Page<Object> page = new Page<>(criteria.getPage(), criteria.getSize());
|
||||
return new ResponseEntity<>(databaseService.queryAll(criteria, page),HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Log("新增数据库")
|
||||
@ApiOperation(value = "新增数据库")
|
||||
@PostMapping
|
||||
@PreAuthorize("@el.check('database:add')")
|
||||
public ResponseEntity<Object> createDatabase(@Validated @RequestBody Database resources){
|
||||
databaseService.create(resources);
|
||||
return new ResponseEntity<>(HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@Log("修改数据库")
|
||||
@ApiOperation(value = "修改数据库")
|
||||
@PutMapping
|
||||
@PreAuthorize("@el.check('database:edit')")
|
||||
public ResponseEntity<Object> updateDatabase(@Validated @RequestBody Database resources){
|
||||
databaseService.update(resources);
|
||||
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
@Log("删除数据库")
|
||||
@ApiOperation(value = "删除数据库")
|
||||
@DeleteMapping
|
||||
@PreAuthorize("@el.check('database:del')")
|
||||
public ResponseEntity<Object> deleteDatabase(@RequestBody Set<String> ids){
|
||||
databaseService.delete(ids);
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Log("测试数据库链接")
|
||||
@ApiOperation(value = "测试数据库链接")
|
||||
@PostMapping("/testConnect")
|
||||
@PreAuthorize("@el.check('database:testConnect')")
|
||||
public ResponseEntity<Object> testConnect(@Validated @RequestBody Database resources){
|
||||
return new ResponseEntity<>(databaseService.testConnection(resources),HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@Log("执行SQL脚本")
|
||||
@ApiOperation(value = "执行SQL脚本")
|
||||
@PostMapping(value = "/upload")
|
||||
@PreAuthorize("@el.check('database:add')")
|
||||
public ResponseEntity<Object> uploadDatabase(@RequestBody MultipartFile file, HttpServletRequest request)throws Exception{
|
||||
String id = request.getParameter("id");
|
||||
Database database = databaseService.getById(id);
|
||||
String fileName;
|
||||
if(database != null){
|
||||
fileName = FileUtil.verifyFilename(file.getOriginalFilename());
|
||||
File executeFile = new File(fileSavePath+fileName);
|
||||
FileUtil.del(executeFile);
|
||||
file.transferTo(executeFile);
|
||||
String result = SqlUtils.executeFile(database.getJdbcUrl(), database.getUserName(), database.getPwd(), executeFile);
|
||||
return new ResponseEntity<>(result,HttpStatus.OK);
|
||||
}else{
|
||||
throw new BadRequestException("Database not exist");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.rest;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import com.fuyuanshen.annotation.Log;
|
||||
import com.fuyuanshen.modules.maint.domain.Deploy;
|
||||
import com.fuyuanshen.modules.maint.domain.DeployHistory;
|
||||
import com.fuyuanshen.modules.maint.domain.dto.DeployQueryCriteria;
|
||||
import com.fuyuanshen.modules.maint.service.DeployService;
|
||||
import com.fuyuanshen.utils.FileUtil;
|
||||
import com.fuyuanshen.utils.PageResult;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@RestController
|
||||
@Api(tags = "运维:部署管理")
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/api/deploy")
|
||||
public class DeployController {
|
||||
|
||||
private final String fileSavePath = FileUtil.getTmpDirPath()+"/";
|
||||
private final DeployService deployService;
|
||||
|
||||
@ApiOperation("导出部署数据")
|
||||
@GetMapping(value = "/download")
|
||||
@PreAuthorize("@el.check('database:list')")
|
||||
public void exportDeployData(HttpServletResponse response, DeployQueryCriteria criteria) throws IOException {
|
||||
deployService.download(deployService.queryAll(criteria), response);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "查询部署")
|
||||
@GetMapping
|
||||
@PreAuthorize("@el.check('deploy:list')")
|
||||
public ResponseEntity<PageResult<Deploy>> queryDeployData(DeployQueryCriteria criteria){
|
||||
Page<Object> page = new Page<>(criteria.getPage(), criteria.getSize());
|
||||
return new ResponseEntity<>(deployService.queryAll(criteria, page),HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Log("新增部署")
|
||||
@ApiOperation(value = "新增部署")
|
||||
@PostMapping
|
||||
@PreAuthorize("@el.check('deploy:add')")
|
||||
public ResponseEntity<Object> createDeploy(@Validated @RequestBody Deploy resources){
|
||||
deployService.create(resources);
|
||||
return new ResponseEntity<>(HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@Log("修改部署")
|
||||
@ApiOperation(value = "修改部署")
|
||||
@PutMapping
|
||||
@PreAuthorize("@el.check('deploy:edit')")
|
||||
public ResponseEntity<Object> updateDeploy(@Validated @RequestBody Deploy resources){
|
||||
deployService.update(resources);
|
||||
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
@Log("删除部署")
|
||||
@ApiOperation(value = "删除部署")
|
||||
@DeleteMapping
|
||||
@PreAuthorize("@el.check('deploy:del')")
|
||||
public ResponseEntity<Object> deleteDeploy(@RequestBody Set<Long> ids){
|
||||
deployService.delete(ids);
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Log("上传文件部署")
|
||||
@ApiOperation(value = "上传文件部署")
|
||||
@PostMapping(value = "/upload")
|
||||
@PreAuthorize("@el.check('deploy:edit')")
|
||||
public ResponseEntity<Object> uploadDeploy(@RequestBody MultipartFile file, HttpServletRequest request)throws Exception{
|
||||
Long id = Long.valueOf(request.getParameter("id"));
|
||||
String fileName = "";
|
||||
if(file != null){
|
||||
fileName = FileUtil.verifyFilename(file.getOriginalFilename());
|
||||
File deployFile = new File(fileSavePath+fileName);
|
||||
FileUtil.del(deployFile);
|
||||
file.transferTo(deployFile);
|
||||
//文件下一步要根据文件名字来
|
||||
deployService.deploy(fileSavePath+fileName ,id);
|
||||
}else{
|
||||
System.out.println("没有找到相对应的文件");
|
||||
}
|
||||
System.out.println("文件上传的原名称为:"+ Objects.requireNonNull(file).getOriginalFilename());
|
||||
Map<String,Object> map = new HashMap<>(2);
|
||||
map.put("errno",0);
|
||||
map.put("id",fileName);
|
||||
return new ResponseEntity<>(map,HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Log("系统还原")
|
||||
@ApiOperation(value = "系统还原")
|
||||
@PostMapping(value = "/serverReduction")
|
||||
@PreAuthorize("@el.check('deploy:edit')")
|
||||
public ResponseEntity<String> serverReduction(@Validated @RequestBody DeployHistory resources){
|
||||
String result = deployService.serverReduction(resources);
|
||||
return new ResponseEntity<>(result,HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Log("服务运行状态")
|
||||
@ApiOperation(value = "服务运行状态")
|
||||
@PostMapping(value = "/serverStatus")
|
||||
@PreAuthorize("@el.check('deploy:edit')")
|
||||
public ResponseEntity<String> serverStatus(@Validated @RequestBody Deploy resources){
|
||||
String result = deployService.serverStatus(resources);
|
||||
return new ResponseEntity<>(result,HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Log("启动服务")
|
||||
@ApiOperation(value = "启动服务")
|
||||
@PostMapping(value = "/startServer")
|
||||
@PreAuthorize("@el.check('deploy:edit')")
|
||||
public ResponseEntity<String> startServer(@Validated @RequestBody Deploy resources){
|
||||
String result = deployService.startServer(resources);
|
||||
return new ResponseEntity<>(result,HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Log("停止服务")
|
||||
@ApiOperation(value = "停止服务")
|
||||
@PostMapping(value = "/stopServer")
|
||||
@PreAuthorize("@el.check('deploy:edit')")
|
||||
public ResponseEntity<String> stopServer(@Validated @RequestBody Deploy resources){
|
||||
String result = deployService.stopServer(resources);
|
||||
return new ResponseEntity<>(result,HttpStatus.OK);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.rest;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import com.fuyuanshen.annotation.Log;
|
||||
import com.fuyuanshen.modules.maint.domain.DeployHistory;
|
||||
import com.fuyuanshen.modules.maint.domain.dto.DeployHistoryQueryCriteria;
|
||||
import com.fuyuanshen.modules.maint.service.DeployHistoryService;
|
||||
import com.fuyuanshen.utils.PageResult;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@Api(tags = "运维:部署历史管理")
|
||||
@RequestMapping("/api/deployHistory")
|
||||
public class DeployHistoryController {
|
||||
|
||||
private final DeployHistoryService deployhistoryService;
|
||||
|
||||
@ApiOperation("导出部署历史数据")
|
||||
@GetMapping(value = "/download")
|
||||
@PreAuthorize("@el.check('deployHistory:list')")
|
||||
public void exportDeployHistory(HttpServletResponse response, DeployHistoryQueryCriteria criteria) throws IOException {
|
||||
deployhistoryService.download(deployhistoryService.queryAll(criteria), response);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "查询部署历史")
|
||||
@GetMapping
|
||||
@PreAuthorize("@el.check('deployHistory:list')")
|
||||
public ResponseEntity<PageResult<DeployHistory>> queryDeployHistory(DeployHistoryQueryCriteria criteria){
|
||||
Page<Object> page = new Page<>(criteria.getPage(), criteria.getSize());
|
||||
return new ResponseEntity<>(deployhistoryService.queryAll(criteria, page),HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Log("删除DeployHistory")
|
||||
@ApiOperation(value = "删除部署历史")
|
||||
@DeleteMapping
|
||||
@PreAuthorize("@el.check('deployHistory:del')")
|
||||
public ResponseEntity<Object> deleteDeployHistory(@RequestBody Set<String> ids){
|
||||
deployhistoryService.delete(ids);
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.rest;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import com.fuyuanshen.annotation.Log;
|
||||
import com.fuyuanshen.modules.maint.domain.Server;
|
||||
import com.fuyuanshen.modules.maint.domain.dto.ServerQueryCriteria;
|
||||
import com.fuyuanshen.modules.maint.service.ServerService;
|
||||
import com.fuyuanshen.utils.PageResult;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@RestController
|
||||
@Api(tags = "运维:服务器管理")
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/api/serverDeploy")
|
||||
public class ServerController {
|
||||
|
||||
private final ServerService serverService;
|
||||
|
||||
@ApiOperation("导出服务器数据")
|
||||
@GetMapping(value = "/download")
|
||||
@PreAuthorize("@el.check('serverDeploy:list')")
|
||||
public void exportServerDeploy(HttpServletResponse response, ServerQueryCriteria criteria) throws IOException {
|
||||
serverService.download(serverService.queryAll(criteria), response);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "查询服务器")
|
||||
@GetMapping
|
||||
@PreAuthorize("@el.check('serverDeploy:list')")
|
||||
public ResponseEntity<PageResult<Server>> queryServerDeploy(ServerQueryCriteria criteria){
|
||||
Page<Object> page = new Page<>(criteria.getPage(), criteria.getSize());
|
||||
return new ResponseEntity<>(serverService.queryAll(criteria, page),HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Log("新增服务器")
|
||||
@ApiOperation(value = "新增服务器")
|
||||
@PostMapping
|
||||
@PreAuthorize("@el.check('serverDeploy:add')")
|
||||
public ResponseEntity<Object> createServerDeploy(@Validated @RequestBody Server resources){
|
||||
serverService.create(resources);
|
||||
return new ResponseEntity<>(HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@Log("修改服务器")
|
||||
@ApiOperation(value = "修改服务器")
|
||||
@PutMapping
|
||||
@PreAuthorize("@el.check('serverDeploy:edit')")
|
||||
public ResponseEntity<Object> updateServerDeploy(@Validated @RequestBody Server resources){
|
||||
serverService.update(resources);
|
||||
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
@Log("删除服务器")
|
||||
@ApiOperation(value = "删除Server")
|
||||
@DeleteMapping
|
||||
@PreAuthorize("@el.check('serverDeploy:del')")
|
||||
public ResponseEntity<Object> deleteServerDeploy(@RequestBody Set<Long> ids){
|
||||
serverService.delete(ids);
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Log("测试连接服务器")
|
||||
@ApiOperation(value = "测试连接服务器")
|
||||
@PostMapping("/testConnect")
|
||||
@PreAuthorize("@el.check('serverDeploy:add')")
|
||||
public ResponseEntity<Object> testConnectServerDeploy(@Validated @RequestBody Server resources){
|
||||
return new ResponseEntity<>(serverService.testConnect(resources),HttpStatus.CREATED);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.fuyuanshen.modules.maint.domain.App;
|
||||
import com.fuyuanshen.modules.maint.domain.dto.AppQueryCriteria;
|
||||
import com.fuyuanshen.utils.PageResult;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
public interface AppService extends IService<App> {
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
* @param criteria 条件
|
||||
* @param page 分页参数
|
||||
* @return /
|
||||
*/
|
||||
PageResult<App> queryAll(AppQueryCriteria criteria, Page<Object> page);
|
||||
|
||||
/**
|
||||
* 查询全部数据
|
||||
*
|
||||
* @param criteria 条件
|
||||
* @return /
|
||||
*/
|
||||
List<App> queryAll(AppQueryCriteria criteria);
|
||||
|
||||
/**
|
||||
* 创建
|
||||
* @param resources /
|
||||
*/
|
||||
void create(App resources);
|
||||
|
||||
/**
|
||||
* 编辑
|
||||
* @param resources /
|
||||
*/
|
||||
void update(App resources);
|
||||
|
||||
/**
|
||||
* 删除
|
||||
* @param ids /
|
||||
*/
|
||||
void delete(Set<Long> ids);
|
||||
|
||||
/**
|
||||
* 导出数据
|
||||
* @param apps /
|
||||
* @param response /
|
||||
* @throws IOException /
|
||||
*/
|
||||
void download(List<App> apps, HttpServletResponse response) throws IOException;
|
||||
}
|
||||
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.fuyuanshen.modules.maint.domain.Database;
|
||||
import com.fuyuanshen.modules.maint.domain.dto.DatabaseQueryCriteria;
|
||||
import com.fuyuanshen.utils.PageResult;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author ZhangHouYing
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
public interface DatabaseService extends IService<Database> {
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
*
|
||||
* @param criteria 条件
|
||||
* @param page 分页参数
|
||||
* @return /
|
||||
*/
|
||||
PageResult<Database> queryAll(DatabaseQueryCriteria criteria, Page<Object> page);
|
||||
|
||||
/**
|
||||
* 查询全部
|
||||
* @param criteria 条件
|
||||
* @return /
|
||||
*/
|
||||
List<Database> queryAll(DatabaseQueryCriteria criteria);
|
||||
|
||||
/**
|
||||
* 创建
|
||||
* @param resources /
|
||||
*/
|
||||
void create(Database resources);
|
||||
|
||||
/**
|
||||
* 编辑
|
||||
* @param resources /
|
||||
*/
|
||||
void update(Database resources);
|
||||
|
||||
/**
|
||||
* 删除
|
||||
* @param ids /
|
||||
*/
|
||||
void delete(Set<String> ids);
|
||||
|
||||
/**
|
||||
* 测试连接
|
||||
* @param resources /
|
||||
* @return /
|
||||
*/
|
||||
boolean testConnection(Database resources);
|
||||
|
||||
/**
|
||||
* 导出数据
|
||||
* @param queryAll /
|
||||
* @param response /
|
||||
* @throws IOException e
|
||||
*/
|
||||
void download(List<Database> queryAll, HttpServletResponse response) throws IOException;
|
||||
}
|
||||
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.fuyuanshen.modules.maint.domain.DeployHistory;
|
||||
import com.fuyuanshen.modules.maint.domain.dto.DeployHistoryQueryCriteria;
|
||||
import com.fuyuanshen.utils.PageResult;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
*/
|
||||
public interface DeployHistoryService extends IService<DeployHistory> {
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
*
|
||||
* @param criteria 条件
|
||||
* @param page 分页参数
|
||||
* @return /
|
||||
*/
|
||||
PageResult<DeployHistory> queryAll(DeployHistoryQueryCriteria criteria, Page<Object> page);
|
||||
|
||||
/**
|
||||
* 查询全部
|
||||
*
|
||||
* @param criteria 条件
|
||||
* @return /
|
||||
*/
|
||||
List<DeployHistory> queryAll(DeployHistoryQueryCriteria criteria);
|
||||
|
||||
/**
|
||||
* 创建
|
||||
* @param resources /
|
||||
*/
|
||||
void create(DeployHistory resources);
|
||||
|
||||
/**
|
||||
* 删除
|
||||
* @param ids /
|
||||
*/
|
||||
void delete(Set<String> ids);
|
||||
|
||||
/**
|
||||
* 导出数据
|
||||
* @param queryAll /
|
||||
* @param response /
|
||||
* @throws IOException /
|
||||
*/
|
||||
void download(List<DeployHistory> queryAll, HttpServletResponse response) throws IOException;
|
||||
}
|
||||
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.fuyuanshen.modules.maint.domain.Deploy;
|
||||
import com.fuyuanshen.modules.maint.domain.DeployHistory;
|
||||
import com.fuyuanshen.modules.maint.domain.dto.DeployQueryCriteria;
|
||||
import com.fuyuanshen.utils.PageResult;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
public interface DeployService extends IService<Deploy> {
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
*
|
||||
* @param criteria 条件
|
||||
* @param page 分页参数
|
||||
* @return /
|
||||
*/
|
||||
PageResult<Deploy> queryAll(DeployQueryCriteria criteria, Page<Object> page);
|
||||
|
||||
/**
|
||||
* 查询全部数据
|
||||
* @param criteria 条件
|
||||
* @return /
|
||||
*/
|
||||
List<Deploy> queryAll(DeployQueryCriteria criteria);
|
||||
|
||||
/**
|
||||
* 创建
|
||||
* @param resources /
|
||||
*/
|
||||
void create(Deploy resources);
|
||||
|
||||
|
||||
/**
|
||||
* 编辑
|
||||
* @param resources /
|
||||
*/
|
||||
void update(Deploy resources);
|
||||
|
||||
/**
|
||||
* 删除
|
||||
* @param ids /
|
||||
*/
|
||||
void delete(Set<Long> ids);
|
||||
|
||||
/**
|
||||
* 部署服务
|
||||
* @param fileSavePath /
|
||||
* @param appId /
|
||||
*/
|
||||
void deploy(String fileSavePath, Long appId);
|
||||
|
||||
/**
|
||||
* 查询部署状态
|
||||
* @param resources /
|
||||
* @return /
|
||||
*/
|
||||
String serverStatus(Deploy resources);
|
||||
/**
|
||||
* 启动服务
|
||||
* @param resources /
|
||||
* @return /
|
||||
*/
|
||||
String startServer(Deploy resources);
|
||||
/**
|
||||
* 停止服务
|
||||
* @param resources /
|
||||
* @return /
|
||||
*/
|
||||
String stopServer(Deploy resources);
|
||||
|
||||
/**
|
||||
* 停止服务
|
||||
* @param resources /
|
||||
* @return /
|
||||
*/
|
||||
String serverReduction(DeployHistory resources);
|
||||
|
||||
/**
|
||||
* 导出数据
|
||||
* @param queryAll /
|
||||
* @param response /
|
||||
* @throws IOException /
|
||||
*/
|
||||
void download(List<Deploy> queryAll, HttpServletResponse response) throws IOException;
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.fuyuanshen.modules.maint.domain.Server;
|
||||
import com.fuyuanshen.modules.maint.domain.dto.ServerQueryCriteria;
|
||||
import com.fuyuanshen.utils.PageResult;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
public interface ServerService extends IService<Server> {
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
*
|
||||
* @param criteria 条件
|
||||
* @param page 分页参数
|
||||
* @return /
|
||||
*/
|
||||
PageResult<Server> queryAll(ServerQueryCriteria criteria, Page<Object> page);
|
||||
|
||||
/**
|
||||
* 查询全部数据
|
||||
* @param criteria 条件
|
||||
* @return /
|
||||
*/
|
||||
List<Server> queryAll(ServerQueryCriteria criteria);
|
||||
|
||||
/**
|
||||
* 创建
|
||||
* @param resources /
|
||||
*/
|
||||
void create(Server resources);
|
||||
|
||||
/**
|
||||
* 编辑
|
||||
* @param resources /
|
||||
*/
|
||||
void update(Server resources);
|
||||
|
||||
/**
|
||||
* 删除
|
||||
* @param ids /
|
||||
*/
|
||||
void delete(Set<Long> ids);
|
||||
|
||||
/**
|
||||
* 根据IP查询
|
||||
*
|
||||
* @param ip /
|
||||
* @return /
|
||||
*/
|
||||
Server findByIp(String ip);
|
||||
|
||||
/**
|
||||
* 测试连接
|
||||
* @param resources /
|
||||
* @return /
|
||||
*/
|
||||
Boolean testConnect(Server resources);
|
||||
|
||||
/**
|
||||
* 导出数据
|
||||
* @param queryAll /
|
||||
* @param response /
|
||||
* @throws IOException /
|
||||
*/
|
||||
void download(List<Server> queryAll, HttpServletResponse response) throws IOException;
|
||||
}
|
||||
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import com.fuyuanshen.exception.BadRequestException;
|
||||
import com.fuyuanshen.modules.maint.domain.App;
|
||||
import com.fuyuanshen.modules.maint.domain.dto.AppQueryCriteria;
|
||||
import com.fuyuanshen.modules.maint.mapper.AppMapper;
|
||||
import com.fuyuanshen.modules.maint.mapper.DeployMapper;
|
||||
import com.fuyuanshen.modules.maint.mapper.DeployServerMapper;
|
||||
import com.fuyuanshen.modules.maint.service.AppService;
|
||||
import com.fuyuanshen.utils.FileUtil;
|
||||
import com.fuyuanshen.utils.PageResult;
|
||||
import com.fuyuanshen.utils.PageUtil;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class AppServiceImpl extends ServiceImpl<AppMapper, App> implements AppService {
|
||||
|
||||
private final AppMapper appMapper;
|
||||
private final DeployMapper deployMapper;
|
||||
private final DeployServerMapper deployServerMapper;
|
||||
|
||||
@Override
|
||||
public PageResult<App> queryAll(AppQueryCriteria criteria, Page<Object> page){
|
||||
return PageUtil.toPage(appMapper.queryAll(criteria, page));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<App> queryAll(AppQueryCriteria criteria){
|
||||
return appMapper.queryAll(criteria);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void create(App resources) {
|
||||
verification(resources);
|
||||
save(resources);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void update(App resources) {
|
||||
verification(resources);
|
||||
App app = getById(resources.getId());
|
||||
app.copy(resources);
|
||||
saveOrUpdate(app);
|
||||
}
|
||||
|
||||
private void verification(App resources){
|
||||
String opt = "/opt";
|
||||
String home = "/home";
|
||||
if (!(resources.getUploadPath().startsWith(opt) || resources.getUploadPath().startsWith(home))) {
|
||||
throw new BadRequestException("文件只能上传在opt目录或者home目录 ");
|
||||
}
|
||||
if (!(resources.getDeployPath().startsWith(opt) || resources.getDeployPath().startsWith(home))) {
|
||||
throw new BadRequestException("文件只能部署在opt目录或者home目录 ");
|
||||
}
|
||||
if (!(resources.getBackupPath().startsWith(opt) || resources.getBackupPath().startsWith(home))) {
|
||||
throw new BadRequestException("文件只能备份在opt目录或者home目录 ");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void delete(Set<Long> ids) {
|
||||
// 删除应用
|
||||
removeBatchByIds(ids);
|
||||
// 删除部署
|
||||
Set<Long> deployIds = deployMapper.getIdByAppIds(ids);
|
||||
if(CollUtil.isNotEmpty(deployIds)){
|
||||
deployServerMapper.deleteByDeployIds(deployIds);
|
||||
deployMapper.deleteBatchIds(deployIds);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void download(List<App> apps, HttpServletResponse response) throws IOException {
|
||||
List<Map<String, Object>> list = new ArrayList<>();
|
||||
for (App app : apps) {
|
||||
Map<String,Object> map = new LinkedHashMap<>();
|
||||
map.put("应用名称", app.getName());
|
||||
map.put("端口", app.getPort());
|
||||
map.put("上传目录", app.getUploadPath());
|
||||
map.put("部署目录", app.getDeployPath());
|
||||
map.put("备份目录", app.getBackupPath());
|
||||
map.put("启动脚本", app.getStartScript());
|
||||
map.put("部署脚本", app.getDeployScript());
|
||||
map.put("创建日期", app.getCreateTime());
|
||||
list.add(map);
|
||||
}
|
||||
FileUtil.downloadExcel(list, response);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.service.impl;
|
||||
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.fuyuanshen.modules.maint.domain.Database;
|
||||
import com.fuyuanshen.modules.maint.domain.dto.DatabaseQueryCriteria;
|
||||
import com.fuyuanshen.modules.maint.mapper.DatabaseMapper;
|
||||
import com.fuyuanshen.modules.maint.service.DatabaseService;
|
||||
import com.fuyuanshen.modules.maint.util.SqlUtils;
|
||||
import com.fuyuanshen.utils.FileUtil;
|
||||
import com.fuyuanshen.utils.PageResult;
|
||||
import com.fuyuanshen.utils.PageUtil;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class DatabaseServiceImpl extends ServiceImpl<DatabaseMapper, Database> implements DatabaseService {
|
||||
|
||||
private final DatabaseMapper databaseMapper;
|
||||
|
||||
@Override
|
||||
public PageResult<Database> queryAll(DatabaseQueryCriteria criteria, Page<Object> page){
|
||||
return PageUtil.toPage(databaseMapper.findAll(criteria, page));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Database> queryAll(DatabaseQueryCriteria criteria){
|
||||
return databaseMapper.findAll(criteria);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void create(Database resources) {
|
||||
resources.setId(IdUtil.simpleUUID());
|
||||
save(resources);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void update(Database resources) {
|
||||
Database database = getById(resources.getId());
|
||||
database.copy(resources);
|
||||
saveOrUpdate(database);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void delete(Set<String> ids) {
|
||||
removeBatchByIds(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean testConnection(Database resources) {
|
||||
try {
|
||||
return SqlUtils.testConnection(resources.getJdbcUrl(), resources.getUserName(), resources.getPwd());
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void download(List<Database> databases, HttpServletResponse response) throws IOException {
|
||||
List<Map<String, Object>> list = new ArrayList<>();
|
||||
for (Database database : databases) {
|
||||
Map<String,Object> map = new LinkedHashMap<>();
|
||||
map.put("数据库名称", database.getName());
|
||||
map.put("数据库连接地址", database.getJdbcUrl());
|
||||
map.put("用户名", database.getUserName());
|
||||
map.put("创建日期", database.getCreateTime());
|
||||
list.add(map);
|
||||
}
|
||||
FileUtil.downloadExcel(list, response);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.service.impl;
|
||||
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import com.fuyuanshen.modules.maint.domain.DeployHistory;
|
||||
import com.fuyuanshen.modules.maint.domain.dto.DeployHistoryQueryCriteria;
|
||||
import com.fuyuanshen.modules.maint.mapper.DeployHistoryMapper;
|
||||
import com.fuyuanshen.modules.maint.service.DeployHistoryService;
|
||||
import com.fuyuanshen.utils.DateUtil;
|
||||
import com.fuyuanshen.utils.FileUtil;
|
||||
import com.fuyuanshen.utils.PageResult;
|
||||
import com.fuyuanshen.utils.PageUtil;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class DeployHistoryServiceImpl extends ServiceImpl<DeployHistoryMapper, DeployHistory> implements DeployHistoryService {
|
||||
|
||||
private final DeployHistoryMapper deployhistoryMapper;
|
||||
|
||||
@Override
|
||||
public PageResult<DeployHistory> queryAll(DeployHistoryQueryCriteria criteria, Page<Object> page){
|
||||
return PageUtil.toPage(deployhistoryMapper.findAll(criteria, page));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DeployHistory> queryAll(DeployHistoryQueryCriteria criteria){
|
||||
return deployhistoryMapper.findAll(criteria);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void create(DeployHistory resources) {
|
||||
resources.setId(IdUtil.simpleUUID());
|
||||
resources.setDeployDate(DateUtil.getTimeStamp());
|
||||
save(resources);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void delete(Set<String> ids) {
|
||||
removeBatchByIds(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void download(List<DeployHistory> deployHistories, HttpServletResponse response) throws IOException {
|
||||
List<Map<String, Object>> list = new ArrayList<>();
|
||||
for (DeployHistory deployHistory : deployHistories) {
|
||||
Map<String,Object> map = new LinkedHashMap<>();
|
||||
map.put("部署编号", deployHistory.getDeployId());
|
||||
map.put("应用名称", deployHistory.getAppName());
|
||||
map.put("部署IP", deployHistory.getIp());
|
||||
map.put("部署时间", deployHistory.getDeployDate());
|
||||
map.put("部署人员", deployHistory.getDeployUser());
|
||||
list.add(map);
|
||||
}
|
||||
FileUtil.downloadExcel(list, response);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,429 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.service.impl;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.fuyuanshen.exception.BadRequestException;
|
||||
import com.fuyuanshen.modules.maint.domain.App;
|
||||
import com.fuyuanshen.modules.maint.domain.Deploy;
|
||||
import com.fuyuanshen.modules.maint.domain.DeployHistory;
|
||||
import com.fuyuanshen.modules.maint.domain.Server;
|
||||
import com.fuyuanshen.modules.maint.domain.dto.DeployQueryCriteria;
|
||||
import com.fuyuanshen.modules.maint.mapper.DeployMapper;
|
||||
import com.fuyuanshen.modules.maint.mapper.DeployServerMapper;
|
||||
import com.fuyuanshen.modules.maint.service.DeployHistoryService;
|
||||
import com.fuyuanshen.modules.maint.service.DeployService;
|
||||
import com.fuyuanshen.modules.maint.service.ServerService;
|
||||
import com.fuyuanshen.modules.maint.util.ExecuteShellUtil;
|
||||
import com.fuyuanshen.modules.maint.util.ScpClientUtil;
|
||||
import com.fuyuanshen.modules.maint.domain.enums.MsgType;
|
||||
import com.fuyuanshen.modules.maint.service.websocket.SocketMsg;
|
||||
import com.fuyuanshen.modules.maint.service.websocket.WebSocketServer;
|
||||
import com.fuyuanshen.utils.FileUtil;
|
||||
import com.fuyuanshen.utils.PageResult;
|
||||
import com.fuyuanshen.utils.PageUtil;
|
||||
import com.fuyuanshen.utils.SecurityUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class DeployServiceImpl extends ServiceImpl<DeployMapper, Deploy> implements DeployService {
|
||||
|
||||
private final String FILE_SEPARATOR = "/";
|
||||
private final DeployMapper deployMapper;
|
||||
private final DeployServerMapper deployServerMapper;
|
||||
private final ServerService serverService;
|
||||
private final DeployHistoryService deployHistoryService;
|
||||
/**
|
||||
* 循环次数
|
||||
*/
|
||||
private final Integer count = 30;
|
||||
|
||||
@Override
|
||||
public PageResult<Deploy> queryAll(DeployQueryCriteria criteria, Page<Object> page) {
|
||||
criteria.setOffset(page.offset());
|
||||
List<Deploy> deploys = deployMapper.findAll(criteria);
|
||||
Long total = deployMapper.countAll(criteria);
|
||||
return PageUtil.toPage(deploys, total);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Deploy> queryAll(DeployQueryCriteria criteria) {
|
||||
return deployMapper.findAll(criteria);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void create(Deploy resources) {
|
||||
resources.setAppId(resources.getApp().getId());
|
||||
save(resources);
|
||||
// 保存关联关系
|
||||
deployServerMapper.insertData(resources.getId(), resources.getDeploys());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void update(Deploy resources) {
|
||||
Deploy deploy = getById(resources.getId());
|
||||
deploy.copy(resources);
|
||||
saveOrUpdate(deploy);
|
||||
// 更新关联关系
|
||||
deployServerMapper.deleteByDeployId(resources.getId());
|
||||
deployServerMapper.insertData(resources.getId(), resources.getDeploys());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void delete(Set<Long> ids) {
|
||||
removeBatchByIds(ids);
|
||||
// 删除关联
|
||||
deployServerMapper.deleteByDeployIds(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deploy(String fileSavePath, Long id) {
|
||||
deployApp(fileSavePath, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fileSavePath 本机路径
|
||||
* @param id ID
|
||||
*/
|
||||
private void deployApp(String fileSavePath, Long id) {
|
||||
Deploy deploy = deployMapper.getDeployById(id);
|
||||
if (deploy == null) {
|
||||
sendMsg("部署信息不存在", MsgType.ERROR);
|
||||
throw new BadRequestException("部署信息不存在");
|
||||
}
|
||||
App app = deploy.getApp();
|
||||
if (app == null) {
|
||||
sendMsg("包对应应用信息不存在", MsgType.ERROR);
|
||||
throw new BadRequestException("包对应应用信息不存在");
|
||||
}
|
||||
int port = app.getPort();
|
||||
//这个是服务器部署路径
|
||||
String uploadPath = app.getUploadPath();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String msg;
|
||||
Set<Server> deploys = deploy.getDeploys();
|
||||
for (Server server : deploys) {
|
||||
String ip = server.getIp();
|
||||
ExecuteShellUtil executeShellUtil = getExecuteShellUtil(ip);
|
||||
//判断是否第一次部署
|
||||
boolean flag = checkFile(executeShellUtil, app);
|
||||
//第一步要确认服务器上有这个目录
|
||||
executeShellUtil.execute("mkdir -p " + app.getUploadPath());
|
||||
executeShellUtil.execute("mkdir -p " + app.getBackupPath());
|
||||
executeShellUtil.execute("mkdir -p " + app.getDeployPath());
|
||||
//上传文件
|
||||
msg = String.format("登陆到服务器:%s", ip);
|
||||
ScpClientUtil scpClientUtil = getScpClientUtil(ip);
|
||||
log.info(msg);
|
||||
sendMsg(msg, MsgType.INFO);
|
||||
msg = String.format("上传文件到服务器:%s<br>目录:%s下,请稍等...", ip, uploadPath);
|
||||
sendMsg(msg, MsgType.INFO);
|
||||
scpClientUtil.putFile(fileSavePath, uploadPath);
|
||||
if (flag) {
|
||||
sendMsg("停止原来应用", MsgType.INFO);
|
||||
//停止应用
|
||||
stopApp(port, executeShellUtil);
|
||||
sendMsg("备份原来应用", MsgType.INFO);
|
||||
//备份应用
|
||||
backupApp(executeShellUtil, ip, app.getDeployPath()+FILE_SEPARATOR, app.getName(), app.getBackupPath()+FILE_SEPARATOR, id);
|
||||
}
|
||||
sendMsg("部署应用", MsgType.INFO);
|
||||
//部署文件,并启动应用
|
||||
String deployScript = app.getDeployScript();
|
||||
executeShellUtil.execute(deployScript);
|
||||
sleep(3);
|
||||
sendMsg("应用部署中,请耐心等待部署结果,或者稍后手动查看部署状态", MsgType.INFO);
|
||||
int i = 0;
|
||||
boolean result = false;
|
||||
// 由于启动应用需要时间,所以需要循环获取状态,如果超过30次,则认为是启动失败
|
||||
while (i++ < count){
|
||||
result = checkIsRunningStatus(port, executeShellUtil);
|
||||
if(result){
|
||||
break;
|
||||
}
|
||||
// 休眠6秒
|
||||
sleep(6);
|
||||
}
|
||||
sb.append("服务器:").append(server.getName()).append("<br>应用:").append(app.getName());
|
||||
sendResultMsg(result, sb);
|
||||
executeShellUtil.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void sleep(int second) {
|
||||
try {
|
||||
Thread.sleep(second * 1000L);
|
||||
} catch (InterruptedException e) {
|
||||
log.error(e.getMessage(),e);
|
||||
}
|
||||
}
|
||||
|
||||
private void backupApp(ExecuteShellUtil executeShellUtil, String ip, String fileSavePath, String appName, String backupPath, Long id) {
|
||||
String deployDate = DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
backupPath += appName + FILE_SEPARATOR + deployDate + "\n";
|
||||
sb.append("mkdir -p ").append(backupPath);
|
||||
sb.append("mv -f ").append(fileSavePath);
|
||||
sb.append(appName).append(" ").append(backupPath);
|
||||
log.info("备份应用脚本:" + sb.toString());
|
||||
executeShellUtil.execute(sb.toString());
|
||||
//还原信息入库
|
||||
DeployHistory deployHistory = new DeployHistory();
|
||||
deployHistory.setAppName(appName);
|
||||
deployHistory.setDeployUser(SecurityUtils.getCurrentUsername());
|
||||
deployHistory.setIp(ip);
|
||||
deployHistory.setDeployId(id);
|
||||
deployHistoryService.create(deployHistory);
|
||||
}
|
||||
|
||||
/**
|
||||
* 停App
|
||||
*
|
||||
* @param port 端口
|
||||
* @param executeShellUtil /
|
||||
*/
|
||||
private void stopApp(int port, ExecuteShellUtil executeShellUtil) {
|
||||
//发送停止命令
|
||||
executeShellUtil.execute(String.format("lsof -i :%d|grep -v \"PID\"|awk '{print \"kill -9\",$2}'|sh", port));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定端口程序是否在运行
|
||||
*
|
||||
* @param port 端口
|
||||
* @param executeShellUtil /
|
||||
* @return true 正在运行 false 已经停止
|
||||
*/
|
||||
private boolean checkIsRunningStatus(int port, ExecuteShellUtil executeShellUtil) {
|
||||
String result = executeShellUtil.executeForResult(String.format("fuser -n tcp %d", port));
|
||||
return result.indexOf("/tcp:")>0;
|
||||
}
|
||||
|
||||
private void sendMsg(String msg, MsgType msgType) {
|
||||
try {
|
||||
WebSocketServer.sendInfo(new SocketMsg(msg, msgType), "deploy");
|
||||
} catch (IOException e) {
|
||||
log.error(e.getMessage(),e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String serverStatus(Deploy resources) {
|
||||
Set<Server> servers = resources.getDeploys();
|
||||
App app = resources.getApp();
|
||||
for (Server server : servers) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
ExecuteShellUtil executeShellUtil = getExecuteShellUtil(server.getIp());
|
||||
sb.append("服务器:").append(server.getName()).append("<br>应用:").append(app.getName());
|
||||
boolean result = checkIsRunningStatus(app.getPort(), executeShellUtil);
|
||||
if (result) {
|
||||
sb.append("<br>正在运行");
|
||||
sendMsg(sb.toString(), MsgType.INFO);
|
||||
} else {
|
||||
sb.append("<br>已停止!");
|
||||
sendMsg(sb.toString(), MsgType.ERROR);
|
||||
}
|
||||
log.info(sb.toString());
|
||||
executeShellUtil.close();
|
||||
}
|
||||
return "执行完毕";
|
||||
}
|
||||
|
||||
private boolean checkFile(ExecuteShellUtil executeShellUtil, App app) {
|
||||
String result = executeShellUtil.executeForResult("find " + app.getDeployPath() + " -name " + app.getName());
|
||||
return result.indexOf(app.getName())>0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动服务
|
||||
* @param resources /
|
||||
* @return /
|
||||
*/
|
||||
@Override
|
||||
public String startServer(Deploy resources) {
|
||||
Set<Server> deploys = resources.getDeploys();
|
||||
App app = resources.getApp();
|
||||
for (Server deploy : deploys) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
ExecuteShellUtil executeShellUtil = getExecuteShellUtil(deploy.getIp());
|
||||
//为了防止重复启动,这里先停止应用
|
||||
stopApp(app.getPort(), executeShellUtil);
|
||||
sb.append("服务器:").append(deploy.getName()).append("<br>应用:").append(app.getName());
|
||||
sendMsg("下发启动命令", MsgType.INFO);
|
||||
executeShellUtil.execute(app.getStartScript());
|
||||
sleep(3);
|
||||
sendMsg("应用启动中,请耐心等待启动结果,或者稍后手动查看运行状态", MsgType.INFO);
|
||||
int i = 0;
|
||||
boolean result = false;
|
||||
// 由于启动应用需要时间,所以需要循环获取状态,如果超过30次,则认为是启动失败
|
||||
while (i++ < count){
|
||||
result = checkIsRunningStatus(app.getPort(), executeShellUtil);
|
||||
if(result){
|
||||
break;
|
||||
}
|
||||
// 休眠6秒
|
||||
sleep(6);
|
||||
}
|
||||
sendResultMsg(result, sb);
|
||||
log.info(sb.toString());
|
||||
executeShellUtil.close();
|
||||
}
|
||||
return "执行完毕";
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止服务
|
||||
* @param resources /
|
||||
* @return /
|
||||
*/
|
||||
@Override
|
||||
public String stopServer(Deploy resources) {
|
||||
Set<Server> deploys = resources.getDeploys();
|
||||
App app = resources.getApp();
|
||||
for (Server deploy : deploys) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
ExecuteShellUtil executeShellUtil = getExecuteShellUtil(deploy.getIp());
|
||||
sb.append("服务器:").append(deploy.getName()).append("<br>应用:").append(app.getName());
|
||||
sendMsg("下发停止命令", MsgType.INFO);
|
||||
//停止应用
|
||||
stopApp(app.getPort(), executeShellUtil);
|
||||
sleep(1);
|
||||
boolean result = checkIsRunningStatus(app.getPort(), executeShellUtil);
|
||||
if (result) {
|
||||
sb.append("<br>关闭失败!");
|
||||
sendMsg(sb.toString(), MsgType.ERROR);
|
||||
} else {
|
||||
sb.append("<br>关闭成功!");
|
||||
sendMsg(sb.toString(), MsgType.INFO);
|
||||
}
|
||||
log.info(sb.toString());
|
||||
executeShellUtil.close();
|
||||
}
|
||||
return "执行完毕";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String serverReduction(DeployHistory resources) {
|
||||
Long deployId = resources.getDeployId();
|
||||
Deploy deployInfo = getById(deployId);
|
||||
String deployDate = DateUtil.format(resources.getDeployDate(), DatePattern.PURE_DATETIME_PATTERN);
|
||||
App app = deployInfo.getApp();
|
||||
if (app == null) {
|
||||
sendMsg("应用信息不存在:" + resources.getAppName(), MsgType.ERROR);
|
||||
throw new BadRequestException("应用信息不存在:" + resources.getAppName());
|
||||
}
|
||||
String backupPath = app.getBackupPath()+FILE_SEPARATOR;
|
||||
backupPath += resources.getAppName() + FILE_SEPARATOR + deployDate;
|
||||
//这个是服务器部署路径
|
||||
String deployPath = app.getDeployPath();
|
||||
String ip = resources.getIp();
|
||||
ExecuteShellUtil executeShellUtil = getExecuteShellUtil(ip);
|
||||
String msg;
|
||||
|
||||
msg = String.format("登陆到服务器:%s", ip);
|
||||
log.info(msg);
|
||||
sendMsg(msg, MsgType.INFO);
|
||||
sendMsg("停止原来应用", MsgType.INFO);
|
||||
//停止应用
|
||||
stopApp(app.getPort(), executeShellUtil);
|
||||
//删除原来应用
|
||||
sendMsg("删除应用", MsgType.INFO);
|
||||
executeShellUtil.execute("rm -rf " + deployPath + FILE_SEPARATOR + resources.getAppName());
|
||||
//还原应用
|
||||
sendMsg("还原应用", MsgType.INFO);
|
||||
executeShellUtil.execute("cp -r " + backupPath + "/. " + deployPath);
|
||||
sendMsg("启动应用", MsgType.INFO);
|
||||
executeShellUtil.execute(app.getStartScript());
|
||||
sendMsg("应用启动中,请耐心等待启动结果,或者稍后手动查看启动状态", MsgType.INFO);
|
||||
int i = 0;
|
||||
boolean result = false;
|
||||
// 由于启动应用需要时间,所以需要循环获取状态,如果超过30次,则认为是启动失败
|
||||
while (i++ < count){
|
||||
result = checkIsRunningStatus(app.getPort(), executeShellUtil);
|
||||
if(result){
|
||||
break;
|
||||
}
|
||||
// 休眠6秒
|
||||
sleep(6);
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("服务器:").append(ip).append("<br>应用:").append(resources.getAppName());
|
||||
sendResultMsg(result, sb);
|
||||
executeShellUtil.close();
|
||||
return "";
|
||||
}
|
||||
|
||||
private ExecuteShellUtil getExecuteShellUtil(String ip) {
|
||||
Server server = serverService.findByIp(ip);
|
||||
if (server == null) {
|
||||
sendMsg("IP对应服务器信息不存在:" + ip, MsgType.ERROR);
|
||||
throw new BadRequestException("IP对应服务器信息不存在:" + ip);
|
||||
}
|
||||
return new ExecuteShellUtil(ip, server.getAccount(), server.getPassword(), server.getPort());
|
||||
}
|
||||
|
||||
private ScpClientUtil getScpClientUtil(String ip) {
|
||||
Server server = serverService.findByIp(ip);
|
||||
if (server == null) {
|
||||
sendMsg("IP对应服务器信息不存在:" + ip, MsgType.ERROR);
|
||||
throw new BadRequestException("IP对应服务器信息不存在:" + ip);
|
||||
}
|
||||
return ScpClientUtil.getInstance(ip, server.getPort(), server.getAccount(), server.getPassword());
|
||||
}
|
||||
|
||||
private void sendResultMsg(boolean result, StringBuilder sb) {
|
||||
if (result) {
|
||||
sb.append("<br>启动成功!");
|
||||
sendMsg(sb.toString(), MsgType.INFO);
|
||||
} else {
|
||||
sb.append("<br>启动失败!");
|
||||
sendMsg(sb.toString(), MsgType.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void download(List<Deploy> deploys, HttpServletResponse response) throws IOException {
|
||||
List<Map<String, Object>> list = new ArrayList<>();
|
||||
for (Deploy deploy : deploys) {
|
||||
Map<String,Object> map = new LinkedHashMap<>();
|
||||
map.put("应用名称", deploy.getApp().getName());
|
||||
map.put("服务器", deploy.getServers());
|
||||
map.put("部署日期", deploy.getCreateTime());
|
||||
list.add(map);
|
||||
}
|
||||
FileUtil.downloadExcel(list, response);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import com.fuyuanshen.modules.maint.domain.Server;
|
||||
import com.fuyuanshen.modules.maint.domain.dto.ServerQueryCriteria;
|
||||
import com.fuyuanshen.modules.maint.mapper.DeployServerMapper;
|
||||
import com.fuyuanshen.modules.maint.mapper.ServerMapper;
|
||||
import com.fuyuanshen.modules.maint.service.ServerService;
|
||||
import com.fuyuanshen.modules.maint.util.ExecuteShellUtil;
|
||||
import com.fuyuanshen.utils.FileUtil;
|
||||
import com.fuyuanshen.utils.PageResult;
|
||||
import com.fuyuanshen.utils.PageUtil;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ServerServiceImpl extends ServiceImpl<ServerMapper, Server> implements ServerService {
|
||||
|
||||
private final ServerMapper serverMapper;
|
||||
private final DeployServerMapper deployServerMapper;
|
||||
|
||||
@Override
|
||||
public PageResult<Server> queryAll(ServerQueryCriteria criteria, Page<Object> page){
|
||||
return PageUtil.toPage(serverMapper.findAll(criteria, page));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Server> queryAll(ServerQueryCriteria criteria){
|
||||
return serverMapper.findAll(criteria);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Server findByIp(String ip) {
|
||||
return serverMapper.findByIp(ip);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean testConnect(Server resources) {
|
||||
ExecuteShellUtil executeShellUtil = null;
|
||||
try {
|
||||
executeShellUtil = new ExecuteShellUtil(resources.getIp(), resources.getAccount(), resources.getPassword(),resources.getPort());
|
||||
return executeShellUtil.execute("ls")==0;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}finally {
|
||||
if (executeShellUtil != null) {
|
||||
executeShellUtil.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void create(Server resources) {
|
||||
save(resources);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void update(Server resources) {
|
||||
Server server = getById(resources.getId());
|
||||
server.copy(resources);
|
||||
saveOrUpdate(server);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void delete(Set<Long> ids) {
|
||||
removeBatchByIds(ids);
|
||||
// 删除与之关联的服务
|
||||
deployServerMapper.deleteByServerIds(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void download(List<Server> servers, HttpServletResponse response) throws IOException {
|
||||
List<Map<String, Object>> list = new ArrayList<>();
|
||||
for (Server deploy : servers) {
|
||||
Map<String,Object> map = new LinkedHashMap<>();
|
||||
map.put("服务器名称", deploy.getName());
|
||||
map.put("服务器IP", deploy.getIp());
|
||||
map.put("端口", deploy.getPort());
|
||||
map.put("账号", deploy.getAccount());
|
||||
map.put("创建日期", deploy.getCreateTime());
|
||||
list.add(map);
|
||||
}
|
||||
FileUtil.downloadExcel(list, response);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.service.websocket;
|
||||
|
||||
import lombok.Data;
|
||||
import com.fuyuanshen.modules.maint.domain.enums.MsgType;
|
||||
|
||||
/**
|
||||
* @author ZhangHouYing
|
||||
* @date 2019-08-10 9:55
|
||||
*/
|
||||
@Data
|
||||
public class SocketMsg {
|
||||
private String msg;
|
||||
private MsgType msgType;
|
||||
|
||||
public SocketMsg(String msg, MsgType msgType) {
|
||||
this.msg = msg;
|
||||
this.msgType = msgType;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.service.websocket;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import javax.websocket.*;
|
||||
import javax.websocket.server.PathParam;
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
/**
|
||||
* @author ZhangHouYing
|
||||
* @date 2019-08-10 15:46
|
||||
*/
|
||||
@ServerEndpoint("/webSocket/{sid}")
|
||||
@Slf4j
|
||||
@Component
|
||||
public class WebSocketServer {
|
||||
|
||||
/**
|
||||
* concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
|
||||
*/
|
||||
private static final CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<>();
|
||||
|
||||
/**
|
||||
* 与某个客户端的连接会话,需要通过它来给客户端发送数据
|
||||
*/
|
||||
private Session session;
|
||||
|
||||
/**
|
||||
* 接收sid
|
||||
*/
|
||||
private String sid="";
|
||||
/**
|
||||
* 连接建立成功调用的方法
|
||||
* */
|
||||
@OnOpen
|
||||
public void onOpen(Session session,@PathParam("sid") String sid) {
|
||||
this.session = session;
|
||||
//如果存在就先删除一个,防止重复推送消息
|
||||
webSocketSet.removeIf(webSocket -> webSocket.sid.equals(sid));
|
||||
webSocketSet.add(this);
|
||||
this.sid=sid;
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接关闭调用的方法
|
||||
*/
|
||||
@OnClose
|
||||
public void onClose() {
|
||||
webSocketSet.remove(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 收到客户端消息后调用的方法
|
||||
* @param message 客户端发送过来的消息*/
|
||||
@OnMessage
|
||||
public void onMessage(String message, Session session) {
|
||||
log.info("收到来"+sid+"的信息:"+message);
|
||||
//群发消息
|
||||
for (WebSocketServer item : webSocketSet) {
|
||||
try {
|
||||
item.sendMessage(message);
|
||||
} catch (IOException e) {
|
||||
log.error(e.getMessage(),e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OnError
|
||||
public void onError(Session session, Throwable error) {
|
||||
log.error("发生错误", error);
|
||||
}
|
||||
/**
|
||||
* 实现服务器主动推送
|
||||
*/
|
||||
private void sendMessage(String message) throws IOException {
|
||||
this.session.getBasicRemote().sendText(message);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 群发自定义消息
|
||||
* */
|
||||
public static void sendInfo(SocketMsg socketMsg,@PathParam("sid") String sid) throws IOException {
|
||||
String message = JSON.toJSONString(socketMsg);
|
||||
log.info("推送消息到"+sid+",推送内容:"+message);
|
||||
for (WebSocketServer item : webSocketSet) {
|
||||
try {
|
||||
//这里可以设定只推送给这个sid的,为null则全部推送
|
||||
if(sid==null) {
|
||||
item.sendMessage(message);
|
||||
}else if(item.sid.equals(sid)){
|
||||
item.sendMessage(message);
|
||||
}
|
||||
} catch (IOException ignored) { }
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
WebSocketServer that = (WebSocketServer) o;
|
||||
return Objects.equals(session, that.session) &&
|
||||
Objects.equals(sid, that.sid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(session, sid);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.util;
|
||||
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import com.jcraft.jsch.ChannelShell;
|
||||
import com.jcraft.jsch.JSch;
|
||||
import com.jcraft.jsch.Session;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* 执行shell命令
|
||||
*
|
||||
* @author ZhangHouYing
|
||||
* @date 2019/8/10
|
||||
*/
|
||||
@Slf4j
|
||||
public class ExecuteShellUtil {
|
||||
|
||||
private Vector<String> stdout;
|
||||
|
||||
Session session;
|
||||
|
||||
public ExecuteShellUtil(final String ipAddress, final String username, final String password,int port) {
|
||||
try {
|
||||
JSch jsch = new JSch();
|
||||
session = jsch.getSession(username, ipAddress, port);
|
||||
session.setPassword(password);
|
||||
session.setConfig("StrictHostKeyChecking", "no");
|
||||
session.connect(3000);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(),e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public int execute(final String command) {
|
||||
int returnCode = 0;
|
||||
ChannelShell channel = null;
|
||||
PrintWriter printWriter = null;
|
||||
BufferedReader input = null;
|
||||
stdout = new Vector<>();
|
||||
try {
|
||||
channel = (ChannelShell) session.openChannel("shell");
|
||||
channel.connect();
|
||||
input = new BufferedReader(new InputStreamReader(channel.getInputStream()));
|
||||
printWriter = new PrintWriter(channel.getOutputStream());
|
||||
printWriter.println(command);
|
||||
printWriter.println("exit");
|
||||
printWriter.flush();
|
||||
log.info("The remote command is: ");
|
||||
String line;
|
||||
while ((line = input.readLine()) != null) {
|
||||
stdout.add(line);
|
||||
System.out.println(line);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(),e);
|
||||
return -1;
|
||||
}finally {
|
||||
IoUtil.close(printWriter);
|
||||
IoUtil.close(input);
|
||||
if (channel != null) {
|
||||
channel.disconnect();
|
||||
}
|
||||
}
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
public void close(){
|
||||
if (session != null) {
|
||||
session.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
public String executeForResult(String command) {
|
||||
execute(command);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String str : stdout) {
|
||||
sb.append(str);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.util;
|
||||
|
||||
import ch.ethz.ssh2.Connection;
|
||||
import ch.ethz.ssh2.SCPClient;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.fuyuanshen.utils.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* 远程执行linux命令
|
||||
* @author ZhangHouYing
|
||||
* @date 2019-08-10 10:06
|
||||
*/
|
||||
public class ScpClientUtil {
|
||||
|
||||
private final String ip;
|
||||
private final int port;
|
||||
private final String username;
|
||||
private final String password;
|
||||
|
||||
static private final Map<String,ScpClientUtil> instance = Maps.newHashMap();
|
||||
|
||||
static synchronized public ScpClientUtil getInstance(String ip, int port, String username, String password) {
|
||||
instance.computeIfAbsent(ip, i -> new ScpClientUtil(i, port, username, password));
|
||||
return instance.get(ip);
|
||||
}
|
||||
|
||||
public ScpClientUtil(String ip, int port, String username, String password) {
|
||||
this.ip = ip;
|
||||
this.port = port;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public void getFile(String remoteFile, String localTargetDirectory) {
|
||||
Connection conn = new Connection(ip, port);
|
||||
try {
|
||||
conn.connect();
|
||||
boolean isAuthenticated = conn.authenticateWithPassword(username, password);
|
||||
if (!isAuthenticated) {
|
||||
System.err.println("authentication failed");
|
||||
}
|
||||
SCPClient client = new SCPClient(conn);
|
||||
client.get(remoteFile, localTargetDirectory);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(SCPClient.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}finally{
|
||||
conn.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void putFile(String localFile, String remoteTargetDirectory) {
|
||||
putFile(localFile, null, remoteTargetDirectory);
|
||||
}
|
||||
|
||||
public void putFile(String localFile, String remoteFileName, String remoteTargetDirectory) {
|
||||
putFile(localFile, remoteFileName, remoteTargetDirectory,null);
|
||||
}
|
||||
|
||||
public void putFile(String localFile, String remoteFileName, String remoteTargetDirectory, String mode) {
|
||||
Connection conn = new Connection(ip, port);
|
||||
try {
|
||||
conn.connect();
|
||||
boolean isAuthenticated = conn.authenticateWithPassword(username, password);
|
||||
if (!isAuthenticated) {
|
||||
System.err.println("authentication failed");
|
||||
}
|
||||
SCPClient client = new SCPClient(conn);
|
||||
if (StringUtils.isBlank(mode)) {
|
||||
mode = "0600";
|
||||
}
|
||||
if (remoteFileName == null) {
|
||||
client.put(localFile, remoteTargetDirectory);
|
||||
} else {
|
||||
client.put(localFile, remoteFileName, remoteTargetDirectory, mode);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ScpClientUtil.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}finally{
|
||||
conn.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.maint.util;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import com.alibaba.druid.util.StringUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.fuyuanshen.modules.maint.domain.enums.DataTypeEnum;
|
||||
import com.fuyuanshen.utils.CloseUtil;
|
||||
import javax.sql.DataSource;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.sql.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author /
|
||||
*/
|
||||
@Slf4j
|
||||
public class SqlUtils {
|
||||
|
||||
/**
|
||||
* 获取数据源
|
||||
*
|
||||
* @param jdbcUrl /
|
||||
* @param userName /
|
||||
* @param password /
|
||||
* @return DataSource
|
||||
*/
|
||||
private static DataSource getDataSource(String jdbcUrl, String userName, String password) {
|
||||
DruidDataSource druidDataSource = new DruidDataSource();
|
||||
String className;
|
||||
try {
|
||||
className = DriverManager.getDriver(jdbcUrl.trim()).getClass().getName();
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException("Get class name error: =" + jdbcUrl);
|
||||
}
|
||||
if (StringUtils.isEmpty(className)) {
|
||||
DataTypeEnum dataTypeEnum = DataTypeEnum.urlOf(jdbcUrl);
|
||||
if (null == dataTypeEnum) {
|
||||
throw new RuntimeException("Not supported data type: jdbcUrl=" + jdbcUrl);
|
||||
}
|
||||
druidDataSource.setDriverClassName(dataTypeEnum.getDriver());
|
||||
} else {
|
||||
druidDataSource.setDriverClassName(className);
|
||||
}
|
||||
|
||||
// 去掉不安全的参数
|
||||
jdbcUrl = sanitizeJdbcUrl(jdbcUrl);
|
||||
|
||||
druidDataSource.setUrl(jdbcUrl);
|
||||
druidDataSource.setUsername(userName);
|
||||
druidDataSource.setPassword(password);
|
||||
// 配置获取连接等待超时的时间
|
||||
druidDataSource.setMaxWait(3000);
|
||||
// 配置初始化大小、最小、最大
|
||||
druidDataSource.setInitialSize(1);
|
||||
druidDataSource.setMinIdle(1);
|
||||
druidDataSource.setMaxActive(1);
|
||||
|
||||
// 如果链接出现异常则直接判定为失败而不是一直重试
|
||||
druidDataSource.setBreakAfterAcquireFailure(true);
|
||||
try {
|
||||
druidDataSource.init();
|
||||
} catch (SQLException e) {
|
||||
log.error("Exception during pool initialization", e);
|
||||
throw new RuntimeException(e.getMessage());
|
||||
}
|
||||
|
||||
return druidDataSource;
|
||||
}
|
||||
|
||||
private static Connection getConnection(String jdbcUrl, String userName, String password) {
|
||||
DataSource dataSource = getDataSource(jdbcUrl, userName, password);
|
||||
Connection connection = null;
|
||||
try {
|
||||
connection = dataSource.getConnection();
|
||||
} catch (Exception ignored) {}
|
||||
try {
|
||||
int timeOut = 5;
|
||||
if (null == connection || connection.isClosed() || !connection.isValid(timeOut)) {
|
||||
log.info("connection is closed or invalid, retry get connection!");
|
||||
connection = dataSource.getConnection();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("create connection error, jdbcUrl: {}", jdbcUrl);
|
||||
throw new RuntimeException("create connection error, jdbcUrl: " + jdbcUrl);
|
||||
} finally {
|
||||
CloseUtil.close(connection);
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
|
||||
private static void releaseConnection(Connection connection) {
|
||||
if (null != connection) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(),e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean testConnection(String jdbcUrl, String userName, String password) {
|
||||
Connection connection = null;
|
||||
try {
|
||||
connection = getConnection(jdbcUrl, userName, password);
|
||||
if (null != connection) {
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Get connection failed:{}", e.getMessage());
|
||||
} finally {
|
||||
releaseConnection(connection);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String executeFile(String jdbcUrl, String userName, String password, File sqlFile) {
|
||||
Connection connection = getConnection(jdbcUrl, userName, password);
|
||||
try {
|
||||
batchExecute(connection, readSqlList(sqlFile));
|
||||
} catch (Exception e) {
|
||||
log.error("sql脚本执行发生异常:{}",e.getMessage());
|
||||
return e.getMessage();
|
||||
}finally {
|
||||
releaseConnection(connection);
|
||||
}
|
||||
return "success";
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量执行sql
|
||||
* @param connection /
|
||||
* @param sqlList /
|
||||
*/
|
||||
public static void batchExecute(Connection connection, List<String> sqlList) {
|
||||
try (Statement st = connection.createStatement()) {
|
||||
for (String sql : sqlList) {
|
||||
// 去除末尾的分号
|
||||
if (sql.endsWith(";")) {
|
||||
sql = sql.substring(0, sql.length() - 1);
|
||||
}
|
||||
// 检查 SQL 语句是否为空
|
||||
if (!sql.trim().isEmpty()) {
|
||||
st.addBatch(sql);
|
||||
}
|
||||
}
|
||||
st.executeBatch();
|
||||
} catch (SQLException e) {
|
||||
log.error("SQL脚本批量执行发生异常: {},错误代码: {}", e.getMessage(), e.getErrorCode());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将文件中的sql语句以;为单位读取到列表中
|
||||
* @param sqlFile /
|
||||
* @return /
|
||||
*/
|
||||
private static List<String> readSqlList(File sqlFile) {
|
||||
List<String> sqlList = new ArrayList<>();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
try (BufferedReader reader = Files.newBufferedReader(sqlFile.toPath(), StandardCharsets.UTF_8)) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
log.info("line: {}", line);
|
||||
sb.append(line.trim());
|
||||
|
||||
if (line.trim().endsWith(";")) {
|
||||
sqlList.add(sb.toString());
|
||||
// 清空 StringBuilder
|
||||
sb.setLength(0);
|
||||
} else {
|
||||
// 在行之间加一个空格
|
||||
sb.append(" ");
|
||||
}
|
||||
}
|
||||
if (sb.length() > 0) {
|
||||
sqlList.add(sb.toString().trim());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("读取SQL文件时发生异常: {}", e.getMessage());
|
||||
}
|
||||
return sqlList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 去除不安全的参数
|
||||
* @param jdbcUrl /
|
||||
* @return /
|
||||
*/
|
||||
private static String sanitizeJdbcUrl(String jdbcUrl) {
|
||||
// 定义不安全参数和其安全替代值
|
||||
String[][] unsafeParams = {
|
||||
// allowLoadLocalInfile:允许使用 LOAD DATA LOCAL INFILE,可能导致文件泄露
|
||||
{"allowLoadLocalInfile", "false"},
|
||||
// allowUrlInLocalInfile:允许在 LOAD DATA LOCAL INFILE 中使用 URL,可能导致未经授权的文件访问
|
||||
{"allowUrlInLocalInfile", "false"},
|
||||
// autoDeserialize:允许自动反序列化对象,可能导致反序列化漏洞
|
||||
{"autoDeserialize", "false"},
|
||||
// allowNanAndInf:允许使用 NaN 和 Infinity 作为数字值,可能导致不一致的数据处理
|
||||
{"allowNanAndInf", "false"},
|
||||
// allowMultiQueries:允许在一个语句中执行多个查询,可能导致 SQL 注入攻击
|
||||
{"allowMultiQueries", "false"},
|
||||
// allowPublicKeyRetrieval:允许从服务器检索公钥,可能导致中间人攻击
|
||||
{"allowPublicKeyRetrieval", "false"}
|
||||
};
|
||||
|
||||
// 替换不安全的参数
|
||||
for (String[] param : unsafeParams) {
|
||||
jdbcUrl = jdbcUrl.replaceAll("(?i)" + param[0] + "=true", param[0] + "=" + param[1]);
|
||||
}
|
||||
return jdbcUrl;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.quartz.config;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import com.fuyuanshen.modules.quartz.domain.QuartzJob;
|
||||
import com.fuyuanshen.modules.quartz.mapper.QuartzJobMapper;
|
||||
import com.fuyuanshen.modules.quartz.utils.QuartzManage;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.stereotype.Component;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2019-01-07
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class JobRunner implements ApplicationRunner {
|
||||
private static final Logger log = LoggerFactory.getLogger(JobRunner.class);
|
||||
private final QuartzJobMapper quartzJobMapper;
|
||||
private final QuartzManage quartzManage;
|
||||
|
||||
/**
|
||||
* 项目启动时重新激活启用的定时任务
|
||||
*
|
||||
* @param applicationArguments /
|
||||
*/
|
||||
@Override
|
||||
public void run(ApplicationArguments applicationArguments) {
|
||||
List<QuartzJob> quartzJobs = quartzJobMapper.findByIsPauseIsFalse();
|
||||
quartzJobs.forEach(quartzManage::addJob);
|
||||
log.info("Timing task injection complete");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.quartz.config;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.quartz.spi.TriggerFiredBundle;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.scheduling.quartz.AdaptableJobFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 定时任务配置
|
||||
* @author /
|
||||
* @date 2019-01-07
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
@Scope("singleton")
|
||||
public class QuartzConfig {
|
||||
|
||||
/**
|
||||
* 解决Job中注入Spring Bean为null的问题
|
||||
*/
|
||||
@Component("quartzJobFactory")
|
||||
public static class QuartzJobFactory extends AdaptableJobFactory {
|
||||
|
||||
private final AutowireCapableBeanFactory capableBeanFactory;
|
||||
|
||||
@Autowired
|
||||
public QuartzJobFactory(AutowireCapableBeanFactory capableBeanFactory) {
|
||||
this.capableBeanFactory = capableBeanFactory;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Object createJobInstance(@NonNull TriggerFiredBundle bundle) throws Exception {
|
||||
try {
|
||||
// 调用父类的方法,把Job注入到spring中
|
||||
Object jobInstance = super.createJobInstance(bundle);
|
||||
capableBeanFactory.autowireBean(jobInstance);
|
||||
log.debug("Job instance created and autowired: {}", jobInstance.getClass().getName());
|
||||
return jobInstance;
|
||||
} catch (Exception e) {
|
||||
log.error("Error creating job instance for bundle: {}", bundle, e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.quartz.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import com.fuyuanshen.base.BaseEntity;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2019-01-07
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("sys_quartz_job")
|
||||
public class QuartzJob extends BaseEntity implements Serializable {
|
||||
|
||||
public static final String JOB_KEY = "JOB_KEY";
|
||||
|
||||
@TableId(value = "job_id", type = IdType.AUTO)
|
||||
@NotNull(groups = {Update.class})
|
||||
private Long id;
|
||||
|
||||
@TableField(exist = false)
|
||||
@ApiModelProperty(value = "用于子任务唯一标识", hidden = true)
|
||||
private String uuid;
|
||||
|
||||
@ApiModelProperty(value = "定时器名称")
|
||||
private String jobName;
|
||||
|
||||
@NotBlank
|
||||
@ApiModelProperty(value = "Bean名称")
|
||||
private String beanName;
|
||||
|
||||
@NotBlank
|
||||
@ApiModelProperty(value = "方法名称")
|
||||
private String methodName;
|
||||
|
||||
@ApiModelProperty(value = "参数")
|
||||
private String params;
|
||||
|
||||
@NotBlank
|
||||
@ApiModelProperty(value = "cron表达式")
|
||||
private String cronExpression;
|
||||
|
||||
@ApiModelProperty(value = "状态,暂时或启动")
|
||||
private Boolean isPause = false;
|
||||
|
||||
@ApiModelProperty(value = "负责人")
|
||||
private String personInCharge;
|
||||
|
||||
@ApiModelProperty(value = "报警邮箱")
|
||||
private String email;
|
||||
|
||||
@ApiModelProperty(value = "子任务")
|
||||
private String subTask;
|
||||
|
||||
@ApiModelProperty(value = "失败后暂停")
|
||||
private Boolean pauseAfterFailure;
|
||||
|
||||
@NotBlank
|
||||
@ApiModelProperty(value = "备注")
|
||||
private String description;
|
||||
}
|
||||
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.quartz.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
import java.sql.Timestamp;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2019-01-07
|
||||
*/
|
||||
@Data
|
||||
@TableName("sys_quartz_log")
|
||||
public class QuartzLog implements Serializable {
|
||||
|
||||
@TableId(value = "log_id", type = IdType.AUTO)
|
||||
@ApiModelProperty(value = "ID", hidden = true)
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty(value = "任务名称", hidden = true)
|
||||
private String jobName;
|
||||
|
||||
@ApiModelProperty(value = "bean名称", hidden = true)
|
||||
private String beanName;
|
||||
|
||||
@ApiModelProperty(value = "方法名称", hidden = true)
|
||||
private String methodName;
|
||||
|
||||
@ApiModelProperty(value = "参数", hidden = true)
|
||||
private String params;
|
||||
|
||||
@ApiModelProperty(value = "cron表达式", hidden = true)
|
||||
private String cronExpression;
|
||||
|
||||
@ApiModelProperty(value = "状态", hidden = true)
|
||||
private Boolean isSuccess;
|
||||
|
||||
@ApiModelProperty(value = "异常详情", hidden = true)
|
||||
private String exceptionDetail;
|
||||
|
||||
@ApiModelProperty(value = "执行耗时", hidden = true)
|
||||
private Long time;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
@ApiModelProperty(value = "创建时间", hidden = true)
|
||||
private Timestamp createTime;
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.quartz.domain.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2019-6-4 10:33:02
|
||||
*/
|
||||
@Data
|
||||
public class QuartzJobQueryCriteria {
|
||||
|
||||
@ApiModelProperty(value = "定时任务名称")
|
||||
private String jobName;
|
||||
|
||||
@ApiModelProperty(value = "是否成功")
|
||||
private Boolean isSuccess;
|
||||
|
||||
@ApiModelProperty(value = "创建时间")
|
||||
private List<Timestamp> createTime;
|
||||
|
||||
@ApiModelProperty(value = "页码", example = "1")
|
||||
private Integer page = 1;
|
||||
|
||||
@ApiModelProperty(value = "每页数据量", example = "10")
|
||||
private Integer size = 10;
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.quartz.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.fuyuanshen.modules.quartz.domain.QuartzJob;
|
||||
import com.fuyuanshen.modules.quartz.domain.dto.QuartzJobQueryCriteria;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @description
|
||||
* @date 2023-06-12
|
||||
**/
|
||||
@Mapper
|
||||
public interface QuartzJobMapper extends BaseMapper<QuartzJob> {
|
||||
|
||||
IPage<QuartzJob> findAll(@Param("criteria") QuartzJobQueryCriteria criteria, Page<Object> page);
|
||||
|
||||
List<QuartzJob> findAll(@Param("criteria") QuartzJobQueryCriteria criteria);
|
||||
|
||||
List<QuartzJob> findByIsPauseIsFalse();
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.quartz.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.fuyuanshen.modules.quartz.domain.QuartzLog;
|
||||
import com.fuyuanshen.modules.quartz.domain.dto.QuartzJobQueryCriteria;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @description
|
||||
* @date 2023-06-12
|
||||
**/
|
||||
@Mapper
|
||||
public interface QuartzLogMapper extends BaseMapper<QuartzLog> {
|
||||
|
||||
IPage<QuartzLog> findAll(@Param("criteria") QuartzJobQueryCriteria criteria, Page<Object> page);
|
||||
|
||||
List<QuartzLog> findAll(@Param("criteria") QuartzJobQueryCriteria criteria);
|
||||
}
|
||||
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.quartz.rest;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.fuyuanshen.annotation.Log;
|
||||
import com.fuyuanshen.exception.BadRequestException;
|
||||
import com.fuyuanshen.modules.quartz.domain.QuartzJob;
|
||||
import com.fuyuanshen.modules.quartz.domain.QuartzLog;
|
||||
import com.fuyuanshen.modules.quartz.service.QuartzJobService;
|
||||
import com.fuyuanshen.modules.quartz.domain.dto.QuartzJobQueryCriteria;
|
||||
import com.fuyuanshen.utils.PageResult;
|
||||
import com.fuyuanshen.utils.SpringBeanHolder;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2019-01-07
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/api/jobs")
|
||||
@Api(tags = "系统:定时任务管理")
|
||||
public class QuartzJobController {
|
||||
|
||||
private static final String ENTITY_NAME = "quartzJob";
|
||||
private final QuartzJobService quartzJobService;
|
||||
|
||||
@ApiOperation("查询定时任务")
|
||||
@GetMapping
|
||||
@PreAuthorize("@el.check('timing:list')")
|
||||
public ResponseEntity<PageResult<QuartzJob>> queryQuartzJob(QuartzJobQueryCriteria criteria){
|
||||
Page<Object> page = new Page<>(criteria.getPage(), criteria.getSize());
|
||||
return new ResponseEntity<>(quartzJobService.queryAll(criteria,page), HttpStatus.OK);
|
||||
}
|
||||
|
||||
@ApiOperation("导出任务数据")
|
||||
@GetMapping(value = "/download")
|
||||
@PreAuthorize("@el.check('timing:list')")
|
||||
public void exportQuartzJob(HttpServletResponse response, QuartzJobQueryCriteria criteria) throws IOException {
|
||||
quartzJobService.download(quartzJobService.queryAll(criteria), response);
|
||||
}
|
||||
|
||||
@ApiOperation("导出日志数据")
|
||||
@GetMapping(value = "/logs/download")
|
||||
@PreAuthorize("@el.check('timing:list')")
|
||||
public void exportQuartzJobLog(HttpServletResponse response, QuartzJobQueryCriteria criteria) throws IOException {
|
||||
quartzJobService.downloadLog(quartzJobService.queryAllLog(criteria), response);
|
||||
}
|
||||
|
||||
@ApiOperation("查询任务执行日志")
|
||||
@GetMapping(value = "/logs")
|
||||
@PreAuthorize("@el.check('timing:list')")
|
||||
public ResponseEntity<PageResult<QuartzLog>> queryQuartzJobLog(QuartzJobQueryCriteria criteria){
|
||||
Page<Object> page = new Page<>(criteria.getPage(), criteria.getSize());
|
||||
return new ResponseEntity<>(quartzJobService.queryAllLog(criteria,page), HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Log("新增定时任务")
|
||||
@ApiOperation("新增定时任务")
|
||||
@PostMapping
|
||||
@PreAuthorize("@el.check('timing:add')")
|
||||
public ResponseEntity<Object> createQuartzJob(@Validated @RequestBody QuartzJob resources){
|
||||
if (resources.getId() != null) {
|
||||
throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID");
|
||||
}
|
||||
// 验证Bean是不是合法的,合法的定时任务 Bean 需要用 @Service 定义
|
||||
checkBean(resources.getBeanName());
|
||||
quartzJobService.create(resources);
|
||||
return new ResponseEntity<>(HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@Log("修改定时任务")
|
||||
@ApiOperation("修改定时任务")
|
||||
@PutMapping
|
||||
@PreAuthorize("@el.check('timing:edit')")
|
||||
public ResponseEntity<Object> updateQuartzJob(@Validated(QuartzJob.Update.class) @RequestBody QuartzJob resources){
|
||||
// 验证Bean是不是合法的,合法的定时任务 Bean 需要用 @Service 定义
|
||||
checkBean(resources.getBeanName());
|
||||
quartzJobService.update(resources);
|
||||
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
@Log("更改定时任务状态")
|
||||
@ApiOperation("更改定时任务状态")
|
||||
@PutMapping(value = "/{id}")
|
||||
@PreAuthorize("@el.check('timing:edit')")
|
||||
public ResponseEntity<Object> updateQuartzJobStatus(@PathVariable Long id){
|
||||
quartzJobService.updateIsPause(quartzJobService.getById(id));
|
||||
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
@Log("执行定时任务")
|
||||
@ApiOperation("执行定时任务")
|
||||
@PutMapping(value = "/exec/{id}")
|
||||
@PreAuthorize("@el.check('timing:edit')")
|
||||
public ResponseEntity<Object> executionQuartzJob(@PathVariable Long id){
|
||||
quartzJobService.execution(quartzJobService.getById(id));
|
||||
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
@Log("删除定时任务")
|
||||
@ApiOperation("删除定时任务")
|
||||
@DeleteMapping
|
||||
@PreAuthorize("@el.check('timing:del')")
|
||||
public ResponseEntity<Object> deleteQuartzJob(@RequestBody Set<Long> ids){
|
||||
quartzJobService.delete(ids);
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证Bean是不是合法的,合法的定时任务 Bean 需要用 @Service 定义
|
||||
* @param beanName Bean名称
|
||||
*/
|
||||
private void checkBean(String beanName){
|
||||
// 避免调用攻击者可以从SpringContextHolder获得控制jdbcTemplate类
|
||||
// 并使用getDeclaredMethod调用jdbcTemplate的queryForMap函数,执行任意sql命令。
|
||||
if(!SpringBeanHolder.getAllServiceBeanName().contains(beanName)){
|
||||
throw new BadRequestException("非法的 Bean,请重新输入!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.quartz.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.fuyuanshen.modules.quartz.domain.QuartzJob;
|
||||
import com.fuyuanshen.modules.quartz.domain.QuartzLog;
|
||||
import com.fuyuanshen.modules.quartz.domain.dto.QuartzJobQueryCriteria;
|
||||
import com.fuyuanshen.utils.PageResult;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2019-01-07
|
||||
*/
|
||||
public interface QuartzJobService extends IService<QuartzJob> {
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
*
|
||||
* @param criteria 条件
|
||||
* @param page 分页参数
|
||||
* @return /
|
||||
*/
|
||||
PageResult<QuartzJob> queryAll(QuartzJobQueryCriteria criteria, Page<Object> page);
|
||||
|
||||
/**
|
||||
* 查询全部
|
||||
* @param criteria 条件
|
||||
* @return /
|
||||
*/
|
||||
List<QuartzJob> queryAll(QuartzJobQueryCriteria criteria);
|
||||
|
||||
/**
|
||||
* 分页查询日志
|
||||
*
|
||||
* @param criteria 条件
|
||||
* @param page 分页参数
|
||||
* @return /
|
||||
*/
|
||||
PageResult<QuartzLog> queryAllLog(QuartzJobQueryCriteria criteria, Page<Object> page);
|
||||
|
||||
/**
|
||||
* 查询全部
|
||||
* @param criteria 条件
|
||||
* @return /
|
||||
*/
|
||||
List<QuartzLog> queryAllLog(QuartzJobQueryCriteria criteria);
|
||||
|
||||
/**
|
||||
* 创建
|
||||
* @param resources /
|
||||
*/
|
||||
void create(QuartzJob resources);
|
||||
|
||||
/**
|
||||
* 编辑
|
||||
* @param resources /
|
||||
*/
|
||||
void update(QuartzJob resources);
|
||||
|
||||
/**
|
||||
* 删除任务
|
||||
* @param ids /
|
||||
*/
|
||||
void delete(Set<Long> ids);
|
||||
|
||||
/**
|
||||
* 更改定时任务状态
|
||||
* @param quartzJob /
|
||||
*/
|
||||
void updateIsPause(QuartzJob quartzJob);
|
||||
|
||||
/**
|
||||
* 立即执行定时任务
|
||||
* @param quartzJob /
|
||||
*/
|
||||
void execution(QuartzJob quartzJob);
|
||||
|
||||
/**
|
||||
* 导出定时任务
|
||||
* @param queryAll 待导出的数据
|
||||
* @param response /
|
||||
* @throws IOException /
|
||||
*/
|
||||
void download(List<QuartzJob> queryAll, HttpServletResponse response) throws IOException;
|
||||
|
||||
/**
|
||||
* 导出定时任务日志
|
||||
* @param queryAllLog 待导出的数据
|
||||
* @param response /
|
||||
* @throws IOException /
|
||||
*/
|
||||
void downloadLog(List<QuartzLog> queryAllLog, HttpServletResponse response) throws IOException;
|
||||
|
||||
/**
|
||||
* 执行子任务
|
||||
* @param tasks /
|
||||
* @throws InterruptedException /
|
||||
*/
|
||||
void executionSubJob(String[] tasks) throws InterruptedException;
|
||||
}
|
||||
@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.quartz.service.impl;
|
||||
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import com.fuyuanshen.exception.BadRequestException;
|
||||
import com.fuyuanshen.modules.quartz.domain.QuartzJob;
|
||||
import com.fuyuanshen.modules.quartz.domain.QuartzLog;
|
||||
import com.fuyuanshen.modules.quartz.mapper.QuartzJobMapper;
|
||||
import com.fuyuanshen.modules.quartz.mapper.QuartzLogMapper;
|
||||
import com.fuyuanshen.modules.quartz.service.QuartzJobService;
|
||||
import com.fuyuanshen.modules.quartz.domain.dto.QuartzJobQueryCriteria;
|
||||
import com.fuyuanshen.modules.quartz.utils.QuartzManage;
|
||||
import com.fuyuanshen.utils.*;
|
||||
import org.quartz.CronExpression;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2019-01-07
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service(value = "quartzJobService")
|
||||
public class QuartzJobServiceImpl extends ServiceImpl<QuartzJobMapper, QuartzJob> implements QuartzJobService {
|
||||
|
||||
private final QuartzJobMapper quartzJobMapper;
|
||||
private final QuartzLogMapper quartzLogMapper;
|
||||
private final QuartzManage quartzManage;
|
||||
private final RedisUtils redisUtils;
|
||||
|
||||
@Override
|
||||
public PageResult<QuartzJob> queryAll(QuartzJobQueryCriteria criteria, Page<Object> page){
|
||||
return PageUtil.toPage(quartzJobMapper.findAll(criteria, page));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<QuartzLog> queryAllLog(QuartzJobQueryCriteria criteria, Page<Object> page){
|
||||
return PageUtil.toPage(quartzLogMapper.findAll(criteria, page));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<QuartzJob> queryAll(QuartzJobQueryCriteria criteria) {
|
||||
return quartzJobMapper.findAll(criteria);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<QuartzLog> queryAllLog(QuartzJobQueryCriteria criteria) {
|
||||
return quartzLogMapper.findAll(criteria);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void create(QuartzJob resources) {
|
||||
if (!CronExpression.isValidExpression(resources.getCronExpression())){
|
||||
throw new BadRequestException("cron表达式格式错误");
|
||||
}
|
||||
save(resources);
|
||||
quartzManage.addJob(resources);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void update(QuartzJob resources) {
|
||||
if (!CronExpression.isValidExpression(resources.getCronExpression())){
|
||||
throw new BadRequestException("cron表达式格式错误");
|
||||
}
|
||||
if(StringUtils.isNotBlank(resources.getSubTask())){
|
||||
List<String> tasks = Arrays.asList(resources.getSubTask().split("[,,]"));
|
||||
if (tasks.contains(resources.getId().toString())) {
|
||||
throw new BadRequestException("子任务中不能添加当前任务ID");
|
||||
}
|
||||
}
|
||||
saveOrUpdate(resources);
|
||||
quartzManage.updateJobCron(resources);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateIsPause(QuartzJob quartzJob) {
|
||||
// 置换暂停状态
|
||||
if (quartzJob.getIsPause()) {
|
||||
quartzManage.resumeJob(quartzJob);
|
||||
quartzJob.setIsPause(false);
|
||||
} else {
|
||||
quartzManage.pauseJob(quartzJob);
|
||||
quartzJob.setIsPause(true);
|
||||
}
|
||||
saveOrUpdate(quartzJob);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execution(QuartzJob quartzJob) {
|
||||
quartzManage.runJobNow(quartzJob);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void delete(Set<Long> ids) {
|
||||
for (Long id : ids) {
|
||||
QuartzJob quartzJob = getById(id);
|
||||
quartzManage.deleteJob(quartzJob);
|
||||
removeById(quartzJob);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void executionSubJob(String[] tasks) throws InterruptedException {
|
||||
for (String id : tasks) {
|
||||
if (StrUtil.isBlank(id)) {
|
||||
// 如果是手动清除子任务id,会出现id为空字符串的问题
|
||||
continue;
|
||||
}
|
||||
QuartzJob quartzJob = getById(Long.parseLong(id));
|
||||
// 执行任务
|
||||
String uuid = IdUtil.simpleUUID();
|
||||
quartzJob.setUuid(uuid);
|
||||
// 执行任务
|
||||
execution(quartzJob);
|
||||
// 获取执行状态,如果执行失败则停止后面的子任务执行
|
||||
Boolean result = redisUtils.get(uuid, Boolean.class);
|
||||
while (result == null) {
|
||||
// 休眠5秒,再次获取子任务执行情况
|
||||
Thread.sleep(5000);
|
||||
result = redisUtils.get(uuid, Boolean.class);
|
||||
}
|
||||
if(!result){
|
||||
redisUtils.del(uuid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void download(List<QuartzJob> quartzJobs, HttpServletResponse response) throws IOException {
|
||||
List<Map<String, Object>> list = new ArrayList<>();
|
||||
for (QuartzJob quartzJob : quartzJobs) {
|
||||
Map<String,Object> map = new LinkedHashMap<>();
|
||||
map.put("任务名称", quartzJob.getJobName());
|
||||
map.put("Bean名称", quartzJob.getBeanName());
|
||||
map.put("执行方法", quartzJob.getMethodName());
|
||||
map.put("参数", quartzJob.getParams());
|
||||
map.put("表达式", quartzJob.getCronExpression());
|
||||
map.put("状态", quartzJob.getIsPause() ? "暂停中" : "运行中");
|
||||
map.put("描述", quartzJob.getDescription());
|
||||
map.put("创建日期", quartzJob.getCreateTime());
|
||||
list.add(map);
|
||||
}
|
||||
FileUtil.downloadExcel(list, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void downloadLog(List<QuartzLog> queryAllLog, HttpServletResponse response) throws IOException {
|
||||
List<Map<String, Object>> list = new ArrayList<>();
|
||||
for (QuartzLog quartzLog : queryAllLog) {
|
||||
Map<String,Object> map = new LinkedHashMap<>();
|
||||
map.put("任务名称", quartzLog.getJobName());
|
||||
map.put("Bean名称", quartzLog.getBeanName());
|
||||
map.put("执行方法", quartzLog.getMethodName());
|
||||
map.put("参数", quartzLog.getParams());
|
||||
map.put("表达式", quartzLog.getCronExpression());
|
||||
map.put("异常详情", quartzLog.getExceptionDetail());
|
||||
map.put("耗时/毫秒", quartzLog.getTime());
|
||||
map.put("状态", quartzLog.getIsSuccess() ? "成功" : "失败");
|
||||
map.put("创建日期", quartzLog.getCreateTime());
|
||||
list.add(map);
|
||||
}
|
||||
FileUtil.downloadExcel(list, response);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.quartz.task;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 测试用
|
||||
* @author Zheng Jie
|
||||
* @date 2019-01-08
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class TestTask {
|
||||
|
||||
public void run(){
|
||||
log.info("run 执行成功");
|
||||
}
|
||||
|
||||
public void run1(String str){
|
||||
log.info("run1 执行成功,参数为: {}", str);
|
||||
}
|
||||
|
||||
public void run2(){
|
||||
log.info("run2 执行成功");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.quartz.utils;
|
||||
|
||||
import cn.hutool.extra.template.Template;
|
||||
import cn.hutool.extra.template.TemplateConfig;
|
||||
import cn.hutool.extra.template.TemplateEngine;
|
||||
import cn.hutool.extra.template.TemplateUtil;
|
||||
import com.fuyuanshen.domain.dto.EmailDto;
|
||||
import com.fuyuanshen.modules.quartz.domain.QuartzJob;
|
||||
import com.fuyuanshen.modules.quartz.domain.QuartzLog;
|
||||
import com.fuyuanshen.modules.quartz.mapper.QuartzLogMapper;
|
||||
import com.fuyuanshen.modules.quartz.service.QuartzJobService;
|
||||
import com.fuyuanshen.service.EmailService;
|
||||
import com.fuyuanshen.utils.RedisUtils;
|
||||
import com.fuyuanshen.utils.SpringBeanHolder;
|
||||
import com.fuyuanshen.utils.StringUtils;
|
||||
import com.fuyuanshen.utils.ThrowableUtil;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
import org.springframework.scheduling.quartz.QuartzJobBean;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
/**
|
||||
* 参考人人开源,<a href="https://gitee.com/renrenio/renren-security">...</a>
|
||||
* @author /
|
||||
* @date 2019-01-07
|
||||
*/
|
||||
public class ExecutionJob extends QuartzJobBean {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
// 此处仅供参考,可根据任务执行情况自定义线程池参数
|
||||
private final ThreadPoolTaskExecutor executor = SpringBeanHolder.getBean("taskAsync");
|
||||
|
||||
@Override
|
||||
public void executeInternal(JobExecutionContext context) {
|
||||
// 获取任务
|
||||
QuartzJob quartzJob = (QuartzJob) context.getMergedJobDataMap().get(QuartzJob.JOB_KEY);
|
||||
// 获取spring bean
|
||||
QuartzLogMapper quartzLogMapper = SpringBeanHolder.getBean(QuartzLogMapper.class);
|
||||
QuartzJobService quartzJobService = SpringBeanHolder.getBean(QuartzJobService.class);
|
||||
RedisUtils redisUtils = SpringBeanHolder.getBean(RedisUtils.class);
|
||||
|
||||
String uuid = quartzJob.getUuid();
|
||||
|
||||
QuartzLog log = new QuartzLog();
|
||||
log.setJobName(quartzJob.getJobName());
|
||||
log.setBeanName(quartzJob.getBeanName());
|
||||
log.setMethodName(quartzJob.getMethodName());
|
||||
log.setParams(quartzJob.getParams());
|
||||
long startTime = System.currentTimeMillis();
|
||||
log.setCronExpression(quartzJob.getCronExpression());
|
||||
try {
|
||||
// 执行任务
|
||||
QuartzRunnable task = new QuartzRunnable(quartzJob.getBeanName(), quartzJob.getMethodName(), quartzJob.getParams());
|
||||
Future<?> future = executor.submit(task);
|
||||
future.get();
|
||||
long times = System.currentTimeMillis() - startTime;
|
||||
log.setTime(times);
|
||||
if(StringUtils.isNotBlank(uuid)) {
|
||||
redisUtils.set(uuid, true);
|
||||
}
|
||||
// 任务状态
|
||||
log.setIsSuccess(true);
|
||||
logger.info("任务执行成功,任务名称:{}, 执行时间:{}毫秒", quartzJob.getJobName(), times);
|
||||
// 判断是否存在子任务
|
||||
if(StringUtils.isNotBlank(quartzJob.getSubTask())){
|
||||
String[] tasks = quartzJob.getSubTask().split("[,,]");
|
||||
// 执行子任务
|
||||
quartzJobService.executionSubJob(tasks);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if(StringUtils.isNotBlank(uuid)) {
|
||||
redisUtils.set(uuid, false);
|
||||
}
|
||||
logger.error("任务执行失败,任务名称:{}", quartzJob.getJobName());
|
||||
long times = System.currentTimeMillis() - startTime;
|
||||
log.setTime(times);
|
||||
// 任务状态 0:成功 1:失败
|
||||
log.setIsSuccess(false);
|
||||
log.setExceptionDetail(ThrowableUtil.getStackTrace(e));
|
||||
// 任务如果失败了则暂停
|
||||
if(quartzJob.getPauseAfterFailure() != null && quartzJob.getPauseAfterFailure()){
|
||||
quartzJob.setIsPause(false);
|
||||
//更新状态
|
||||
quartzJobService.updateIsPause(quartzJob);
|
||||
}
|
||||
if(quartzJob.getEmail() != null){
|
||||
EmailService emailService = SpringBeanHolder.getBean(EmailService.class);
|
||||
// 邮箱报警
|
||||
if(StringUtils.isNoneBlank(quartzJob.getEmail())){
|
||||
EmailDto emailDto = taskAlarm(quartzJob, ThrowableUtil.getStackTrace(e));
|
||||
emailService.send(emailDto, emailService.find());
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
quartzLogMapper.insert(log);
|
||||
}
|
||||
}
|
||||
|
||||
private EmailDto taskAlarm(QuartzJob quartzJob, String msg) {
|
||||
EmailDto emailDto = new EmailDto();
|
||||
emailDto.setSubject("定时任务【"+ quartzJob.getJobName() +"】执行失败,请尽快处理!");
|
||||
Map<String, Object> data = new HashMap<>(16);
|
||||
data.put("task", quartzJob);
|
||||
data.put("msg", msg);
|
||||
TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("template", TemplateConfig.ResourceMode.CLASSPATH));
|
||||
Template template = engine.getTemplate("taskAlarm.ftl");
|
||||
emailDto.setContent(template.render(data));
|
||||
List<String> emails = Arrays.asList(quartzJob.getEmail().split("[,,]"));
|
||||
emailDto.setTos(emails);
|
||||
return emailDto;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.quartz.utils;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.fuyuanshen.exception.BadRequestException;
|
||||
import com.fuyuanshen.modules.quartz.domain.QuartzJob;
|
||||
import org.quartz.*;
|
||||
import org.quartz.impl.triggers.CronTriggerImpl;
|
||||
import org.springframework.stereotype.Component;
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Date;
|
||||
import static org.quartz.TriggerBuilder.newTrigger;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2019-01-07
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class QuartzManage {
|
||||
|
||||
private static final String JOB_NAME = "TASK_";
|
||||
|
||||
@Resource
|
||||
private Scheduler scheduler;
|
||||
|
||||
public void addJob(QuartzJob quartzJob){
|
||||
try {
|
||||
// 构建job信息
|
||||
JobDetail jobDetail = JobBuilder.newJob(ExecutionJob.class).
|
||||
withIdentity(JOB_NAME + quartzJob.getId()).build();
|
||||
|
||||
//通过触发器名和cron 表达式创建 Trigger
|
||||
Trigger cronTrigger = newTrigger()
|
||||
.withIdentity(JOB_NAME + quartzJob.getId())
|
||||
.startNow()
|
||||
.withSchedule(CronScheduleBuilder.cronSchedule(quartzJob.getCronExpression()))
|
||||
.build();
|
||||
|
||||
cronTrigger.getJobDataMap().put(QuartzJob.JOB_KEY, quartzJob);
|
||||
|
||||
//重置启动时间
|
||||
((CronTriggerImpl)cronTrigger).setStartTime(new Date());
|
||||
|
||||
//执行定时任务,如果是持久化的,这里会报错,捕获输出
|
||||
try {
|
||||
scheduler.scheduleJob(jobDetail,cronTrigger);
|
||||
} catch (ObjectAlreadyExistsException e) {
|
||||
log.warn("定时任务已存在,跳过加载");
|
||||
}
|
||||
|
||||
// 暂停任务
|
||||
if (quartzJob.getIsPause()) {
|
||||
pauseJob(quartzJob);
|
||||
}
|
||||
} catch (Exception e){
|
||||
log.error("创建定时任务失败", e);
|
||||
throw new BadRequestException("创建定时任务失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新job cron表达式
|
||||
* @param quartzJob /
|
||||
*/
|
||||
public void updateJobCron(QuartzJob quartzJob){
|
||||
try {
|
||||
TriggerKey triggerKey = TriggerKey.triggerKey(JOB_NAME + quartzJob.getId());
|
||||
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
|
||||
// 如果不存在则创建一个定时任务
|
||||
if(trigger == null){
|
||||
addJob(quartzJob);
|
||||
trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
|
||||
}
|
||||
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzJob.getCronExpression());
|
||||
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
|
||||
//重置启动时间
|
||||
((CronTriggerImpl)trigger).setStartTime(new Date());
|
||||
trigger.getJobDataMap().put(QuartzJob.JOB_KEY,quartzJob);
|
||||
|
||||
scheduler.rescheduleJob(triggerKey, trigger);
|
||||
// 暂停任务
|
||||
if (quartzJob.getIsPause()) {
|
||||
pauseJob(quartzJob);
|
||||
}
|
||||
} catch (Exception e){
|
||||
log.error("更新定时任务失败", e);
|
||||
throw new BadRequestException("更新定时任务失败");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除一个job
|
||||
* @param quartzJob /
|
||||
*/
|
||||
public void deleteJob(QuartzJob quartzJob){
|
||||
try {
|
||||
JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
|
||||
scheduler.pauseJob(jobKey);
|
||||
scheduler.deleteJob(jobKey);
|
||||
} catch (Exception e){
|
||||
log.error("删除定时任务失败", e);
|
||||
throw new BadRequestException("删除定时任务失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复一个job
|
||||
* @param quartzJob /
|
||||
*/
|
||||
public void resumeJob(QuartzJob quartzJob){
|
||||
try {
|
||||
TriggerKey triggerKey = TriggerKey.triggerKey(JOB_NAME + quartzJob.getId());
|
||||
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
|
||||
// 如果不存在则创建一个定时任务
|
||||
if(trigger == null) {
|
||||
addJob(quartzJob);
|
||||
}
|
||||
JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
|
||||
scheduler.resumeJob(jobKey);
|
||||
} catch (Exception e){
|
||||
log.error("恢复定时任务失败", e);
|
||||
throw new BadRequestException("恢复定时任务失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 立即执行job
|
||||
* @param quartzJob /
|
||||
*/
|
||||
public void runJobNow(QuartzJob quartzJob){
|
||||
try {
|
||||
TriggerKey triggerKey = TriggerKey.triggerKey(JOB_NAME + quartzJob.getId());
|
||||
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
|
||||
// 如果不存在则创建一个定时任务
|
||||
if(trigger == null) {
|
||||
addJob(quartzJob);
|
||||
}
|
||||
JobDataMap dataMap = new JobDataMap();
|
||||
dataMap.put(QuartzJob.JOB_KEY, quartzJob);
|
||||
JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
|
||||
scheduler.triggerJob(jobKey,dataMap);
|
||||
} catch (Exception e){
|
||||
log.error("定时任务执行失败", e);
|
||||
throw new BadRequestException("定时任务执行失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停一个job
|
||||
* @param quartzJob /
|
||||
*/
|
||||
public void pauseJob(QuartzJob quartzJob){
|
||||
try {
|
||||
JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
|
||||
scheduler.pauseJob(jobKey);
|
||||
} catch (Exception e){
|
||||
log.error("定时任务暂停失败", e);
|
||||
throw new BadRequestException("定时任务暂停失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.quartz.utils;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.fuyuanshen.utils.SpringBeanHolder;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/**
|
||||
* 执行定时任务
|
||||
* @author /
|
||||
*/
|
||||
@Slf4j
|
||||
public class QuartzRunnable implements Callable<Object> {
|
||||
|
||||
private final Object target;
|
||||
private final Method method;
|
||||
private final String params;
|
||||
|
||||
QuartzRunnable(String beanName, String methodName, String params)
|
||||
throws NoSuchMethodException, SecurityException {
|
||||
this.target = SpringBeanHolder.getBean(beanName);
|
||||
this.params = params;
|
||||
if (StringUtils.isNotBlank(params)) {
|
||||
this.method = target.getClass().getDeclaredMethod(methodName, String.class);
|
||||
} else {
|
||||
this.method = target.getClass().getDeclaredMethod(methodName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({"unchecked","all"})
|
||||
public Object call() throws Exception {
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
if (StringUtils.isNotBlank(params)) {
|
||||
method.invoke(target, params);
|
||||
} else {
|
||||
method.invoke(target);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright 2019-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version loginCode.length.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-loginCode.length.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.security.config;
|
||||
|
||||
import com.wf.captcha.*;
|
||||
import com.wf.captcha.base.Captcha;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import com.fuyuanshen.exception.BadRequestException;
|
||||
import com.fuyuanshen.modules.security.config.enums.LoginCodeEnum;
|
||||
import com.fuyuanshen.utils.StringUtils;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* 登录验证码配置信息
|
||||
* @author liaojinlong
|
||||
* @date 2025-01-13
|
||||
*/
|
||||
@Data
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "login.code")
|
||||
public class CaptchaConfig {
|
||||
|
||||
/**
|
||||
* 验证码配置
|
||||
*/
|
||||
@Getter
|
||||
private LoginCodeEnum codeType;
|
||||
|
||||
/**
|
||||
* 验证码有效期 分钟
|
||||
*/
|
||||
private Long expiration = 5L;
|
||||
|
||||
/**
|
||||
* 验证码内容长度
|
||||
*/
|
||||
private int length = 4;
|
||||
|
||||
/**
|
||||
* 验证码宽度
|
||||
*/
|
||||
private int width = 111;
|
||||
|
||||
/**
|
||||
* 验证码高度
|
||||
*/
|
||||
private int height = 36;
|
||||
|
||||
/**
|
||||
* 验证码字体
|
||||
*/
|
||||
private String fontName;
|
||||
|
||||
/**
|
||||
* 字体大小
|
||||
*/
|
||||
private int fontSize = 25;
|
||||
|
||||
/**
|
||||
* 依据配置信息生产验证码
|
||||
* @return /
|
||||
*/
|
||||
public Captcha getCaptcha() {
|
||||
Captcha captcha;
|
||||
switch (codeType) {
|
||||
case ARITHMETIC:
|
||||
// 算术类型 https://gitee.com/whvse/EasyCaptcha
|
||||
captcha = new FixedArithmeticCaptcha(width, height);
|
||||
// 几位数运算,默认是两位
|
||||
captcha.setLen(length);
|
||||
break;
|
||||
case CHINESE:
|
||||
captcha = new ChineseCaptcha(width, height);
|
||||
captcha.setLen(length);
|
||||
break;
|
||||
case CHINESE_GIF:
|
||||
captcha = new ChineseGifCaptcha(width, height);
|
||||
captcha.setLen(length);
|
||||
break;
|
||||
case GIF:
|
||||
captcha = new GifCaptcha(width, height);
|
||||
captcha.setLen(length);
|
||||
break;
|
||||
case SPEC:
|
||||
captcha = new SpecCaptcha(width, height);
|
||||
captcha.setLen(length);
|
||||
break;
|
||||
default:
|
||||
throw new BadRequestException("验证码配置信息错误!正确配置查看 LoginCodeEnum ");
|
||||
}
|
||||
if(StringUtils.isNotBlank(fontName)){
|
||||
captcha.setFont(new Font(fontName, Font.PLAIN, fontSize));
|
||||
}
|
||||
return captcha;
|
||||
}
|
||||
|
||||
static class FixedArithmeticCaptcha extends ArithmeticCaptcha {
|
||||
public FixedArithmeticCaptcha(int width, int height) {
|
||||
super(width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected char[] alphas() {
|
||||
// 生成随机数字和运算符
|
||||
int n1 = num(1, 10), n2 = num(1, 10);
|
||||
int opt = num(3);
|
||||
|
||||
// 计算结果
|
||||
int res = new int[]{n1 + n2, n1 - n2, n1 * n2}[opt];
|
||||
// 转换为字符运算符
|
||||
char optChar = "+-x".charAt(opt);
|
||||
|
||||
this.setArithmeticString(String.format("%s%c%s=?", n1, optChar, n2));
|
||||
this.chars = String.valueOf(res);
|
||||
|
||||
return chars.toCharArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2019-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version loginCode.length.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-loginCode.length.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.security.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 配置文件读取
|
||||
*
|
||||
* @author liaojinlong
|
||||
* @date loginCode.length0loginCode.length0/6/10 17:loginCode.length6
|
||||
*/
|
||||
@Data
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "login")
|
||||
public class LoginProperties {
|
||||
|
||||
/**
|
||||
* 账号单用户 登录
|
||||
*/
|
||||
private boolean singleLogin = false;
|
||||
|
||||
public static final String cacheKey = "user_login_cache:";
|
||||
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.security.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Jwt参数配置
|
||||
*
|
||||
* @author Zheng Jie
|
||||
* @date 2019年11月28日
|
||||
*/
|
||||
@Data
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "jwt")
|
||||
public class SecurityProperties {
|
||||
|
||||
/**
|
||||
* Request Headers : Authorization
|
||||
*/
|
||||
private String header;
|
||||
|
||||
/**
|
||||
* 令牌前缀,最后留个空格 Bearer
|
||||
*/
|
||||
private String tokenStartWith;
|
||||
|
||||
/**
|
||||
* 必须使用最少88位的Base64对该令牌进行编码
|
||||
*/
|
||||
private String base64Secret;
|
||||
|
||||
/**
|
||||
* 令牌过期时间 此处单位/毫秒
|
||||
*/
|
||||
private Long tokenValidityInSeconds;
|
||||
|
||||
/**
|
||||
* 在线用户 key,根据 key 查询 redis 中在线用户的数据
|
||||
*/
|
||||
private String onlineKey;
|
||||
|
||||
/**
|
||||
* 验证码 key
|
||||
*/
|
||||
private String codeKey;
|
||||
|
||||
/**
|
||||
* token 续期检查
|
||||
*/
|
||||
private Long detect;
|
||||
|
||||
/**
|
||||
* 续期时间
|
||||
*/
|
||||
private Long renew;
|
||||
|
||||
public String getTokenStartWith() {
|
||||
return tokenStartWith + " ";
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.security.config;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import com.fuyuanshen.modules.security.security.*;
|
||||
import com.fuyuanshen.modules.security.service.OnlineUserService;
|
||||
import com.fuyuanshen.utils.AnonTagUtils;
|
||||
import com.fuyuanshen.utils.enums.RequestMethodEnum;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.core.GrantedAuthorityDefaults;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
*/
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
|
||||
public class SpringSecurityConfig {
|
||||
|
||||
private final TokenProvider tokenProvider;
|
||||
private final CorsFilter corsFilter;
|
||||
private final JwtAuthenticationEntryPoint authenticationErrorHandler;
|
||||
private final JwtAccessDeniedHandler jwtAccessDeniedHandler;
|
||||
private final ApplicationContext applicationContext;
|
||||
private final SecurityProperties properties;
|
||||
private final OnlineUserService onlineUserService;
|
||||
|
||||
@Bean
|
||||
GrantedAuthorityDefaults grantedAuthorityDefaults() {
|
||||
// 去除 ROLE_ 前缀
|
||||
return new GrantedAuthorityDefaults("");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
// 密码加密方式
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
@Bean
|
||||
protected SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
|
||||
// 获取匿名标记
|
||||
Map<String, Set<String>> anonymousUrls = AnonTagUtils.getAnonymousUrl(applicationContext);
|
||||
return httpSecurity
|
||||
// 禁用 CSRF
|
||||
.csrf().disable()
|
||||
.addFilter(corsFilter)
|
||||
// 授权异常
|
||||
.exceptionHandling()
|
||||
.authenticationEntryPoint(authenticationErrorHandler)
|
||||
.accessDeniedHandler(jwtAccessDeniedHandler)
|
||||
// 防止iframe 造成跨域
|
||||
.and()
|
||||
.headers()
|
||||
.frameOptions()
|
||||
.disable()
|
||||
// 不创建会话
|
||||
.and()
|
||||
.sessionManagement()
|
||||
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
// 静态资源等等
|
||||
.antMatchers(
|
||||
HttpMethod.GET,
|
||||
"/*.html",
|
||||
"/**/*.html",
|
||||
"/**/*.css",
|
||||
"/**/*.js",
|
||||
"/webSocket/**"
|
||||
).permitAll()
|
||||
// swagger 文档
|
||||
.antMatchers("/swagger-ui.html").permitAll()
|
||||
.antMatchers("/swagger-resources/**").permitAll()
|
||||
.antMatchers("/webjars/**").permitAll()
|
||||
.antMatchers("/*/api-docs").permitAll()
|
||||
// 文件
|
||||
.antMatchers("/avatar/**").permitAll()
|
||||
.antMatchers("/file/**").permitAll()
|
||||
// 阿里巴巴 druid
|
||||
.antMatchers("/druid/**").permitAll()
|
||||
// 放行OPTIONS请求
|
||||
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
|
||||
// 自定义匿名访问所有url放行:允许匿名和带Token访问,细腻化到每个 Request 类型
|
||||
// GET
|
||||
.antMatchers(HttpMethod.GET, anonymousUrls.get(RequestMethodEnum.GET.getType()).toArray(new String[0])).permitAll()
|
||||
// POST
|
||||
.antMatchers(HttpMethod.POST, anonymousUrls.get(RequestMethodEnum.POST.getType()).toArray(new String[0])).permitAll()
|
||||
// PUT
|
||||
.antMatchers(HttpMethod.PUT, anonymousUrls.get(RequestMethodEnum.PUT.getType()).toArray(new String[0])).permitAll()
|
||||
// PATCH
|
||||
.antMatchers(HttpMethod.PATCH, anonymousUrls.get(RequestMethodEnum.PATCH.getType()).toArray(new String[0])).permitAll()
|
||||
// DELETE
|
||||
.antMatchers(HttpMethod.DELETE, anonymousUrls.get(RequestMethodEnum.DELETE.getType()).toArray(new String[0])).permitAll()
|
||||
// 所有类型的接口都放行
|
||||
.antMatchers(anonymousUrls.get(RequestMethodEnum.ALL.getType()).toArray(new String[0])).permitAll()
|
||||
// 所有请求都需要认证
|
||||
.anyRequest().authenticated()
|
||||
.and().apply(securityConfigurerAdapter())
|
||||
.and().build();
|
||||
}
|
||||
|
||||
private TokenConfigurer securityConfigurerAdapter() {
|
||||
return new TokenConfigurer(tokenProvider, properties, onlineUserService);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2019-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.security.config.enums;
|
||||
|
||||
/**
|
||||
* 验证码配置枚举
|
||||
*
|
||||
* @author liaojinlong
|
||||
* @date 2020/6/10 17:40
|
||||
*/
|
||||
|
||||
public enum LoginCodeEnum {
|
||||
/**
|
||||
* 算数
|
||||
*/
|
||||
ARITHMETIC,
|
||||
/**
|
||||
* 中文
|
||||
*/
|
||||
CHINESE,
|
||||
/**
|
||||
* 中文闪图
|
||||
*/
|
||||
CHINESE_GIF,
|
||||
/**
|
||||
* 闪图
|
||||
*/
|
||||
GIF,
|
||||
/**
|
||||
* 静态
|
||||
*/
|
||||
SPEC
|
||||
}
|
||||
@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.security.rest;
|
||||
|
||||
import cn.hutool.core.date.DateTime;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import com.fuyuanshen.annotation.Log;
|
||||
import com.fuyuanshen.annotation.rest.AnonymousDeleteMapping;
|
||||
import com.fuyuanshen.annotation.rest.AnonymousGetMapping;
|
||||
import com.fuyuanshen.annotation.rest.AnonymousPostMapping;
|
||||
import com.fuyuanshen.exception.BadRequestException;
|
||||
import com.fuyuanshen.modules.security.config.CaptchaConfig;
|
||||
import com.fuyuanshen.modules.security.config.LoginProperties;
|
||||
import com.fuyuanshen.modules.security.config.SecurityProperties;
|
||||
import com.fuyuanshen.modules.security.config.enums.LoginCodeEnum;
|
||||
import com.fuyuanshen.modules.security.security.TokenProvider;
|
||||
import com.fuyuanshen.modules.security.service.OnlineUserService;
|
||||
import com.fuyuanshen.modules.security.service.UserDetailsServiceImpl;
|
||||
import com.fuyuanshen.modules.security.service.dto.app.AppAuthUserQuery;
|
||||
import com.fuyuanshen.modules.security.service.dto.app.AppRoleDto;
|
||||
import com.fuyuanshen.modules.security.service.dto.AuthUserDto;
|
||||
import com.fuyuanshen.modules.security.service.dto.JwtUserDto;
|
||||
import com.fuyuanshen.modules.system.domain.app.APPUser;
|
||||
import com.fuyuanshen.modules.system.domain.query.APPUserDto;
|
||||
import com.fuyuanshen.modules.system.mapper.app.APPUserMapper;
|
||||
import com.fuyuanshen.utils.RedisUtils;
|
||||
import com.fuyuanshen.utils.SecurityUtils;
|
||||
import com.fuyuanshen.utils.StringUtils;
|
||||
import com.wf.captcha.base.Captcha;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-23
|
||||
* 授权、根据token获取用户详细信息
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/auth")
|
||||
@RequiredArgsConstructor
|
||||
@Api(tags = "系统:系统授权接口")
|
||||
public class AuthController {
|
||||
|
||||
private final SecurityProperties properties;
|
||||
private final RedisUtils redisUtils;
|
||||
private final OnlineUserService onlineUserService;
|
||||
private final TokenProvider tokenProvider;
|
||||
private final CaptchaConfig captchaConfig;
|
||||
private final LoginProperties loginProperties;
|
||||
private final UserDetailsServiceImpl userDetailsService;
|
||||
private final APPUserMapper appUserMapper;
|
||||
|
||||
@Log("用户登录")
|
||||
@ApiOperation("登录授权")
|
||||
@AnonymousPostMapping(value = "/login")
|
||||
public ResponseEntity<Object> login(@Validated @RequestBody AuthUserDto authUser, HttpServletRequest request) throws Exception {
|
||||
// 密码解密
|
||||
// String password = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey, authUser.getPassword());
|
||||
String password = authUser.getPassword();
|
||||
// 查询验证码
|
||||
String code = redisUtils.get(authUser.getUuid(), String.class);
|
||||
// 清除验证码
|
||||
redisUtils.del(authUser.getUuid());
|
||||
if (StringUtils.isBlank(code)) {
|
||||
throw new BadRequestException("验证码不存在或已过期");
|
||||
}
|
||||
if (StringUtils.isBlank(authUser.getCode()) || !authUser.getCode().equalsIgnoreCase(code)) {
|
||||
throw new BadRequestException("验证码错误");
|
||||
}
|
||||
// 获取用户信息
|
||||
JwtUserDto jwtUser = userDetailsService.loadUserByUsername(authUser.getUsername());
|
||||
// String dbPwd = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey, jwtUser.getPassword());
|
||||
// 验证用户密码
|
||||
/*if (!passwordEncoder.matches(password, jwtUser.getPassword())) {
|
||||
throw new BadRequestException("登录密码错误");
|
||||
}*/
|
||||
if (!password.equals(jwtUser.getPassword())) {
|
||||
throw new BadRequestException("登录密码错误");
|
||||
}
|
||||
|
||||
Authentication authentication = new UsernamePasswordAuthenticationToken(jwtUser, null, jwtUser.getAuthorities());
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
// 生成令牌
|
||||
String token = tokenProvider.createToken(jwtUser);
|
||||
// 返回 token 与 用户信息
|
||||
Map<String, Object> authInfo = new HashMap<String, Object>(2) {{
|
||||
put("token", properties.getTokenStartWith() + token);
|
||||
put("user", jwtUser);
|
||||
}};
|
||||
if (loginProperties.isSingleLogin()) {
|
||||
// 踢掉之前已经登录的token
|
||||
onlineUserService.kickOutForUsername(authUser.getUsername());
|
||||
}
|
||||
// 保存在线信息
|
||||
onlineUserService.save(jwtUser, token, request);
|
||||
|
||||
System.out.println("租户ID");
|
||||
System.out.println(jwtUser.getUser().getTenantId());
|
||||
// 返回登录信息
|
||||
return ResponseEntity.ok(authInfo);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Log("app用户注册")
|
||||
@ApiOperation("app用户注册")
|
||||
@AnonymousPostMapping(value = "/app/register")
|
||||
public ResponseEntity<Boolean> APPRegister(@Validated @RequestBody AppAuthUserQuery authUser, HttpServletRequest request) throws Exception {
|
||||
|
||||
// 校验手机号是否为空
|
||||
if (StringUtils.isBlank(authUser.getPhoneNumber())) {
|
||||
throw new BadRequestException("手机号不能为空");
|
||||
}
|
||||
|
||||
// 验证验证码(示例)
|
||||
int verificationCode = 0000;
|
||||
if (authUser.getVerificationCode() != verificationCode) {
|
||||
throw new BadRequestException("验证码错误");
|
||||
}
|
||||
// 构建用户对象
|
||||
APPUserDto appUserDTO = new APPUserDto();
|
||||
appUserDTO.setUsername(authUser.getPhoneNumber());
|
||||
appUserDTO.setPassword(authUser.getPassword());
|
||||
appUserDTO.setPhoneNumber(authUser.getPhoneNumber());
|
||||
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
appUserDTO.setCreateTime(now);
|
||||
appUserDTO.setUpdateTime(now);
|
||||
|
||||
log.debug("注册参数: {}", appUserDTO);
|
||||
|
||||
// 检查手机号是否已注册
|
||||
APPUser existingUser = appUserMapper.selectByQueryOne(appUserDTO);
|
||||
if (existingUser != null) {
|
||||
throw new BadRequestException("手机号已注册");
|
||||
}
|
||||
|
||||
// 执行注册
|
||||
boolean isRegistered = appUserMapper.createAppUser(appUserDTO);
|
||||
if (!isRegistered) {
|
||||
throw new BadRequestException("注册失败");
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(true);
|
||||
|
||||
}
|
||||
|
||||
@Log("app用户登录")
|
||||
@ApiOperation("app用户登录")
|
||||
@AnonymousPostMapping(value = "/app/login")
|
||||
public ResponseEntity<Object> APPLogin(@Validated @RequestBody AppAuthUserQuery authUser, HttpServletRequest request) throws Exception {
|
||||
|
||||
// 1. 构建查询参数
|
||||
APPUserDto appUserDTO = new APPUserDto();
|
||||
appUserDTO.setPhoneNumber(authUser.getPhoneNumber());
|
||||
appUserDTO.setPassword(authUser.getPassword());
|
||||
|
||||
|
||||
log.debug("登录参数: {}", appUserDTO);
|
||||
|
||||
// 2. 查询用户
|
||||
APPUser appUser = appUserMapper.selectByQueryOne(appUserDTO);
|
||||
if (appUser == null) {
|
||||
log.debug("手机号未注册: {}", authUser.getPhoneNumber());
|
||||
throw new BadRequestException("手机号未注册");
|
||||
}
|
||||
|
||||
// 3. 验证密码
|
||||
if (!appUser.getPassword().equals(authUser.getPassword())) {
|
||||
throw new BadRequestException("登录密码错误");
|
||||
}
|
||||
|
||||
// 4. 加载用户详情
|
||||
JwtUserDto jwtUser = userDetailsService.loadUserByUsername(appUser.getUsername());
|
||||
|
||||
// 5. 创建认证信息
|
||||
Authentication authentication = new UsernamePasswordAuthenticationToken(jwtUser, null, jwtUser.getAuthorities());
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
|
||||
// 6. 生成 Token
|
||||
String token = tokenProvider.createToken(jwtUser);
|
||||
|
||||
// 7. 获取角色权限
|
||||
AppRoleDto appRoleDto = appUserMapper.selectRoleByUserLevel(appUser.getUserLevel());
|
||||
|
||||
// 8. 构建响应数据
|
||||
Map<String, Object> authInfo = new HashMap<>(3) {{
|
||||
put("token", properties.getTokenStartWith() + token);
|
||||
put("user", jwtUser);
|
||||
put("role", appRoleDto);
|
||||
}};
|
||||
|
||||
// 9. 单点登录踢人
|
||||
if (loginProperties.isSingleLogin()) {
|
||||
onlineUserService.kickOutForUsername(authUser.getUsername());
|
||||
}
|
||||
|
||||
// 10. 记录在线状态
|
||||
onlineUserService.save(jwtUser, token, request);
|
||||
|
||||
// 11. 返回结果
|
||||
return ResponseEntity.ok(authInfo);
|
||||
}
|
||||
|
||||
|
||||
@ApiOperation("获取用户信息")
|
||||
@GetMapping(value = "/info")
|
||||
public ResponseEntity<UserDetails> getUserInfo() {
|
||||
JwtUserDto jwtUser = (JwtUserDto) SecurityUtils.getCurrentUser();
|
||||
return ResponseEntity.ok(jwtUser);
|
||||
}
|
||||
|
||||
|
||||
@ApiOperation("获取验证码")
|
||||
@AnonymousGetMapping(value = "/code")
|
||||
public ResponseEntity<Object> getCode() {
|
||||
// 获取运算的结果
|
||||
Captcha captcha = captchaConfig.getCaptcha();
|
||||
String uuid = properties.getCodeKey() + IdUtil.simpleUUID();
|
||||
// 当验证码类型为 arithmetic时且长度 >= 2 时,captcha.text()的结果有几率为浮点型
|
||||
String captchaValue = captcha.text();
|
||||
System.out.println("验证码uuid的值是 = " + uuid);
|
||||
System.out.println("验证码的值是 = " + captchaValue);
|
||||
if (captcha.getCharType() - 1 == LoginCodeEnum.ARITHMETIC.ordinal() && captchaValue.contains(".")) {
|
||||
captchaValue = captchaValue.split("\\.")[0];
|
||||
}
|
||||
// 保存
|
||||
redisUtils.set(uuid, captchaValue, captchaConfig.getExpiration(), TimeUnit.MINUTES);
|
||||
// 验证码信息
|
||||
Map<String, Object> imgResult = new HashMap<String, Object>(2) {{
|
||||
put("img", captcha.toBase64());
|
||||
put("uuid", uuid);
|
||||
}};
|
||||
return ResponseEntity.ok(imgResult);
|
||||
}
|
||||
|
||||
|
||||
@ApiOperation("退出登录")
|
||||
@AnonymousDeleteMapping(value = "/logout")
|
||||
public ResponseEntity<Object> logout(HttpServletRequest request) {
|
||||
String token = tokenProvider.getToken(request);
|
||||
onlineUserService.logout(token);
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.security.rest;
|
||||
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import com.fuyuanshen.modules.security.service.OnlineUserService;
|
||||
import com.fuyuanshen.modules.security.service.dto.OnlineUserDto;
|
||||
import com.fuyuanshen.utils.EncryptUtils;
|
||||
import com.fuyuanshen.utils.PageResult;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
*/
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/auth/online")
|
||||
@Api(tags = "系统:在线用户管理")
|
||||
public class OnlineController {
|
||||
|
||||
private final OnlineUserService onlineUserService;
|
||||
|
||||
@ApiOperation("查询在线用户")
|
||||
@GetMapping
|
||||
@PreAuthorize("@el.check()")
|
||||
public ResponseEntity<PageResult<OnlineUserDto>> queryOnlineUser(String username, Pageable pageable){
|
||||
return new ResponseEntity<>(onlineUserService.getAll(username, pageable),HttpStatus.OK);
|
||||
}
|
||||
|
||||
@ApiOperation("导出数据")
|
||||
@GetMapping(value = "/download")
|
||||
@PreAuthorize("@el.check()")
|
||||
public void exportOnlineUser(HttpServletResponse response, String username) throws IOException {
|
||||
onlineUserService.download(onlineUserService.getAll(username), response);
|
||||
}
|
||||
|
||||
@ApiOperation("踢出用户")
|
||||
@DeleteMapping
|
||||
@PreAuthorize("@el.check()")
|
||||
public ResponseEntity<Object> deleteOnlineUser(@RequestBody Set<String> keys) throws Exception {
|
||||
for (String token : keys) {
|
||||
// 解密Key
|
||||
token = EncryptUtils.desDecrypt(token);
|
||||
onlineUserService.logout(token);
|
||||
}
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.security.security;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fuyuanshen.exception.handler.ApiError;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||
import org.springframework.stereotype.Component;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
*/
|
||||
@Component
|
||||
public class JwtAccessDeniedHandler implements AccessDeniedHandler {
|
||||
|
||||
@Override
|
||||
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {
|
||||
//当用户在没有授权的情况下访问受保护的REST资源时,将调用此方法发送403 Forbidden响应
|
||||
response.setStatus(HttpStatus.FORBIDDEN.value());
|
||||
response.setContentType("application/json;charset=UTF-8");
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
String jsonResponse = objectMapper.writeValueAsString(ApiError.error(HttpStatus.FORBIDDEN.value(), "禁止访问,您没有权限访问此资源"));
|
||||
response.getWriter().write(jsonResponse);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.security.security;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.fuyuanshen.exception.handler.ApiError;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.stereotype.Component;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
|
||||
|
||||
@Override
|
||||
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
|
||||
// 当用户尝试访问安全的REST资源而不提供任何凭据时,将调用此方法发送401 响应
|
||||
int code = HttpStatus.UNAUTHORIZED.value();
|
||||
response.setStatus(code);
|
||||
response.setContentType("application/json;charset=UTF-8");
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
String jsonResponse = objectMapper.writeValueAsString(ApiError.error(HttpStatus.UNAUTHORIZED.value(), "登录状态已过期,请重新登录"));
|
||||
response.getWriter().write(jsonResponse);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.security.security;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import com.fuyuanshen.modules.security.config.SecurityProperties;
|
||||
import com.fuyuanshen.modules.security.service.OnlineUserService;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.web.DefaultSecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
|
||||
/**
|
||||
* @author /
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class TokenConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
|
||||
|
||||
private final TokenProvider tokenProvider;
|
||||
private final SecurityProperties properties;
|
||||
private final OnlineUserService onlineUserService;
|
||||
|
||||
@Override
|
||||
public void configure(HttpSecurity http) {
|
||||
TokenFilter customFilter = new TokenFilter(tokenProvider, properties, onlineUserService);
|
||||
http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.security.security;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.fuyuanshen.modules.security.config.SecurityProperties;
|
||||
import com.fuyuanshen.modules.security.service.dto.OnlineUserDto;
|
||||
import com.fuyuanshen.modules.security.service.OnlineUserService;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.filter.GenericFilterBean;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author /
|
||||
*/
|
||||
@Slf4j
|
||||
public class TokenFilter extends GenericFilterBean {
|
||||
|
||||
private final TokenProvider tokenProvider;
|
||||
private final SecurityProperties properties;
|
||||
private final OnlineUserService onlineUserService;
|
||||
|
||||
/**
|
||||
* @param tokenProvider Token
|
||||
* @param properties JWT
|
||||
* @param onlineUserService 用户在线
|
||||
*/
|
||||
public TokenFilter(TokenProvider tokenProvider, SecurityProperties properties, OnlineUserService onlineUserService) {
|
||||
this.properties = properties;
|
||||
this.onlineUserService = onlineUserService;
|
||||
this.tokenProvider = tokenProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws ServletException, IOException {
|
||||
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
|
||||
String token = resolveToken(httpServletRequest);
|
||||
// 对于 Token 为空的不需要去查 Redis
|
||||
if(StrUtil.isNotBlank(token)){
|
||||
// 获取用户Token的Key
|
||||
String loginKey = tokenProvider.loginKey(token);
|
||||
OnlineUserDto onlineUserDto = onlineUserService.getOne(loginKey);
|
||||
// 判断用户在线信息是否为空
|
||||
if (onlineUserDto != null) {
|
||||
// Token 续期判断
|
||||
tokenProvider.checkRenewal(token);
|
||||
// 获取认证信息,设置上下文
|
||||
Authentication authentication = tokenProvider.getAuthentication(token);
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
}
|
||||
}
|
||||
filterChain.doFilter(servletRequest, servletResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初步检测Token
|
||||
*
|
||||
* @param request /
|
||||
* @return /
|
||||
*/
|
||||
private String resolveToken(HttpServletRequest request) {
|
||||
String bearerToken = request.getHeader(properties.getHeader());
|
||||
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(properties.getTokenStartWith())) {
|
||||
// 去掉令牌前缀
|
||||
return bearerToken.replace(properties.getTokenStartWith(), "");
|
||||
} else {
|
||||
log.debug("非法Token:{}", bearerToken);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.security.security;
|
||||
|
||||
import cn.hutool.core.date.DateField;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import io.jsonwebtoken.*;
|
||||
import io.jsonwebtoken.io.Decoders;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.fuyuanshen.modules.security.config.SecurityProperties;
|
||||
import com.fuyuanshen.modules.security.service.dto.JwtUserDto;
|
||||
import com.fuyuanshen.utils.RedisUtils;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.stereotype.Component;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.security.Key;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author /
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class TokenProvider implements InitializingBean {
|
||||
|
||||
private JwtParser jwtParser;
|
||||
private JwtBuilder jwtBuilder;
|
||||
private final RedisUtils redisUtils;
|
||||
private final SecurityProperties properties;
|
||||
public static final String AUTHORITIES_UUID_KEY = "uid";
|
||||
public static final String AUTHORITIES_UID_KEY = "userId";
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
byte[] keyBytes = Decoders.BASE64.decode(properties.getBase64Secret());
|
||||
Key key = Keys.hmacShaKeyFor(keyBytes);
|
||||
jwtParser = Jwts.parserBuilder()
|
||||
.setSigningKey(key)
|
||||
.build();
|
||||
jwtBuilder = Jwts.builder()
|
||||
.signWith(key, SignatureAlgorithm.HS512);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建Token 设置永不过期,
|
||||
* Token 的时间有效性转到Redis 维护
|
||||
* @param user /
|
||||
* @return /
|
||||
*/
|
||||
public String createToken(JwtUserDto user) {
|
||||
// 设置参数
|
||||
Map<String, Object> claims = new HashMap<>(6);
|
||||
// 设置用户ID
|
||||
claims.put(AUTHORITIES_UID_KEY, user.getUser().getId());
|
||||
// 设置UUID,确保每次Token不一样
|
||||
claims.put(AUTHORITIES_UUID_KEY, IdUtil.simpleUUID());
|
||||
return jwtBuilder
|
||||
.setClaims(claims)
|
||||
.setSubject(user.getUsername())
|
||||
.compact();
|
||||
}
|
||||
|
||||
/**
|
||||
* 依据Token 获取鉴权信息
|
||||
*
|
||||
* @param token /
|
||||
* @return /
|
||||
*/
|
||||
Authentication getAuthentication(String token) {
|
||||
Claims claims = getClaims(token);
|
||||
User principal = new User(claims.getSubject(), "******", new ArrayList<>());
|
||||
return new UsernamePasswordAuthenticationToken(principal, token, new ArrayList<>());
|
||||
}
|
||||
|
||||
public Claims getClaims(String token) {
|
||||
return jwtParser
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param token 需要检查的token
|
||||
*/
|
||||
public void checkRenewal(String token) {
|
||||
// 判断是否续期token,计算token的过期时间
|
||||
String loginKey = loginKey(token);
|
||||
long time = redisUtils.getExpire(loginKey) * 1000;
|
||||
Date expireDate = DateUtil.offset(new Date(), DateField.MILLISECOND, (int) time);
|
||||
// 判断当前时间与过期时间的时间差
|
||||
long differ = expireDate.getTime() - System.currentTimeMillis();
|
||||
// 如果在续期检查的范围内,则续期
|
||||
if (differ <= properties.getDetect()) {
|
||||
long renew = time + properties.getRenew();
|
||||
redisUtils.expire(loginKey, renew, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
public String getToken(HttpServletRequest request) {
|
||||
final String requestHeader = request.getHeader(properties.getHeader());
|
||||
if (requestHeader != null && requestHeader.startsWith(properties.getTokenStartWith())) {
|
||||
return requestHeader.substring(7);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取登录用户RedisKey
|
||||
* @param token /
|
||||
* @return key
|
||||
*/
|
||||
public String loginKey(String token) {
|
||||
Claims claims = getClaims(token);
|
||||
return properties.getOnlineKey() + claims.getSubject() + ":" + getId(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取会话编号
|
||||
* @param token /
|
||||
* @return /
|
||||
*/
|
||||
public String getId(String token) {
|
||||
Claims claims = getClaims(token);
|
||||
return claims.get(AUTHORITIES_UUID_KEY, String.class);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.security.service;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.fuyuanshen.modules.security.security.TokenProvider;
|
||||
import com.fuyuanshen.utils.PageResult;
|
||||
import com.fuyuanshen.modules.security.config.SecurityProperties;
|
||||
import com.fuyuanshen.modules.security.service.dto.JwtUserDto;
|
||||
import com.fuyuanshen.modules.security.service.dto.OnlineUserDto;
|
||||
import com.fuyuanshen.utils.*;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2019年10月26日21:56:27
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
@AllArgsConstructor
|
||||
public class OnlineUserService {
|
||||
|
||||
private final SecurityProperties properties;
|
||||
private final TokenProvider tokenProvider;
|
||||
private final RedisUtils redisUtils;
|
||||
|
||||
/**
|
||||
* 保存在线用户信息
|
||||
* @param jwtUserDto /
|
||||
* @param token /
|
||||
* @param request /
|
||||
*/
|
||||
public void save(JwtUserDto jwtUserDto, String token, HttpServletRequest request){
|
||||
String dept = jwtUserDto.getUser().getDept() == null ? null : jwtUserDto.getUser().getDept().getName();
|
||||
String ip = StringUtils.getIp(request);
|
||||
String id = tokenProvider.getId(token);
|
||||
String browser = StringUtils.getBrowser(request);
|
||||
String address = StringUtils.getCityInfo(ip);
|
||||
OnlineUserDto onlineUserDto = null;
|
||||
try {
|
||||
onlineUserDto = new OnlineUserDto(id, jwtUserDto.getUsername(), jwtUserDto.getUser().getNickName(), dept, browser , ip, address, EncryptUtils.desEncrypt(token), new Date());
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(),e);
|
||||
}
|
||||
String loginKey = tokenProvider.loginKey(token);
|
||||
redisUtils.set(loginKey, onlineUserDto, properties.getTokenValidityInSeconds(), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询全部数据
|
||||
* @param username /
|
||||
* @param pageable /
|
||||
* @return /
|
||||
*/
|
||||
public PageResult<OnlineUserDto> getAll(String username, Pageable pageable){
|
||||
List<OnlineUserDto> onlineUserDtos = getAll(username);
|
||||
int pageNumber = pageable.getPageNumber() - 1;
|
||||
return PageUtil.toPage(
|
||||
PageUtil.paging(pageNumber,pageable.getPageSize(), onlineUserDtos),
|
||||
onlineUserDtos.size()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询全部数据,不分页
|
||||
* @param username /
|
||||
* @return /
|
||||
*/
|
||||
public List<OnlineUserDto> getAll(String username){
|
||||
String loginKey = properties.getOnlineKey() +
|
||||
(StringUtils.isBlank(username) ? "" : "*" + username);
|
||||
List<String> keys = redisUtils.scan(loginKey + "*");
|
||||
Collections.reverse(keys);
|
||||
List<OnlineUserDto> onlineUserDtos = new ArrayList<>();
|
||||
for (String key : keys) {
|
||||
onlineUserDtos.add(redisUtils.get(key, OnlineUserDto.class));
|
||||
}
|
||||
onlineUserDtos.sort((o1, o2) -> o2.getLoginTime().compareTo(o1.getLoginTime()));
|
||||
return onlineUserDtos;
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出登录
|
||||
* @param token /
|
||||
*/
|
||||
public void logout(String token) {
|
||||
String loginKey = tokenProvider.loginKey(token);
|
||||
redisUtils.del(loginKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出
|
||||
* @param all /
|
||||
* @param response /
|
||||
* @throws IOException /
|
||||
*/
|
||||
public void download(List<OnlineUserDto> all, HttpServletResponse response) throws IOException {
|
||||
List<Map<String, Object>> list = new ArrayList<>();
|
||||
for (OnlineUserDto user : all) {
|
||||
Map<String,Object> map = new LinkedHashMap<>();
|
||||
map.put("用户名", user.getUserName());
|
||||
map.put("部门", user.getDept());
|
||||
map.put("登录IP", user.getIp());
|
||||
map.put("登录地点", user.getAddress());
|
||||
map.put("浏览器", user.getBrowser());
|
||||
map.put("登录日期", user.getLoginTime());
|
||||
list.add(map);
|
||||
}
|
||||
FileUtil.downloadExcel(list, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询用户
|
||||
* @param key /
|
||||
* @return /
|
||||
*/
|
||||
public OnlineUserDto getOne(String key) {
|
||||
return redisUtils.get(key, OnlineUserDto.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户名强退用户
|
||||
* @param username /
|
||||
*/
|
||||
public void kickOutForUsername(String username) {
|
||||
String loginKey = properties.getOnlineKey() + username + "*";
|
||||
redisUtils.scanDel(loginKey);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.security.service;
|
||||
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import com.fuyuanshen.modules.security.config.LoginProperties;
|
||||
import com.fuyuanshen.modules.security.service.dto.JwtUserDto;
|
||||
import com.fuyuanshen.utils.RedisUtils;
|
||||
import com.fuyuanshen.utils.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @description 用户缓存管理
|
||||
* @date 2022-05-26
|
||||
**/
|
||||
@Component
|
||||
public class UserCacheManager {
|
||||
|
||||
@Resource
|
||||
private RedisUtils redisUtils;
|
||||
@Value("${login.user-cache.idle-time}")
|
||||
private long idleTime;
|
||||
|
||||
/**
|
||||
* 返回用户缓存
|
||||
* @param userName 用户名
|
||||
* @return JwtUserDto
|
||||
*/
|
||||
public JwtUserDto getUserCache(String userName) {
|
||||
// 转小写
|
||||
userName = StringUtils.lowerCase(userName);
|
||||
if (StringUtils.isNotEmpty(userName)) {
|
||||
// 获取数据
|
||||
return redisUtils.get(LoginProperties.cacheKey + userName, JwtUserDto.class);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加缓存到Redis
|
||||
* @param userName 用户名
|
||||
*/
|
||||
@Async
|
||||
public void addUserCache(String userName, JwtUserDto user) {
|
||||
// 转小写
|
||||
userName = StringUtils.lowerCase(userName);
|
||||
if (StringUtils.isNotEmpty(userName)) {
|
||||
// 添加数据, 避免数据同时过期
|
||||
long time = idleTime + RandomUtil.randomInt(900, 1800);
|
||||
redisUtils.set(LoginProperties.cacheKey + userName, user, time);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理用户缓存信息
|
||||
* 用户信息变更时
|
||||
* @param userName 用户名
|
||||
*/
|
||||
@Async
|
||||
public void cleanUserCache(String userName) {
|
||||
// 转小写
|
||||
userName = StringUtils.lowerCase(userName);
|
||||
if (StringUtils.isNotEmpty(userName)) {
|
||||
// 清除数据
|
||||
redisUtils.del(LoginProperties.cacheKey + userName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.security.service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.fuyuanshen.exception.BadRequestException;
|
||||
import com.fuyuanshen.modules.security.service.dto.AuthorityDto;
|
||||
import com.fuyuanshen.modules.security.service.dto.JwtUserDto;
|
||||
import com.fuyuanshen.modules.system.domain.User;
|
||||
import com.fuyuanshen.modules.system.service.DataService;
|
||||
import com.fuyuanshen.modules.system.service.RoleService;
|
||||
import com.fuyuanshen.modules.system.service.UserService;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-22
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service("userDetailsService")
|
||||
public class UserDetailsServiceImpl implements UserDetailsService {
|
||||
|
||||
private final UserService userService;
|
||||
private final RoleService roleService;
|
||||
private final DataService dataService;
|
||||
private final UserCacheManager userCacheManager;
|
||||
|
||||
|
||||
@Override
|
||||
public JwtUserDto loadUserByUsername(String username) {
|
||||
JwtUserDto jwtUserDto = userCacheManager.getUserCache(username);
|
||||
if (jwtUserDto == null) {
|
||||
User user = userService.getLoginData(username);
|
||||
if (user == null) {
|
||||
throw new BadRequestException("用户不存在");
|
||||
} else {
|
||||
if (!user.getEnabled()) {
|
||||
throw new BadRequestException("账号未激活!");
|
||||
}
|
||||
// 获取用户的权限
|
||||
List<AuthorityDto> authorities = roleService.buildPermissions(user);
|
||||
// 初始化JwtUserDto
|
||||
jwtUserDto = new JwtUserDto(user, dataService.getDeptIds(user), authorities);
|
||||
// 添加缓存数据
|
||||
userCacheManager.addUserCache(username, jwtUserDto);
|
||||
}
|
||||
}
|
||||
return jwtUserDto;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.security.service.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-30
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class AuthUserDto {
|
||||
|
||||
@NotBlank
|
||||
@ApiModelProperty(value = "用户名")
|
||||
private String username;
|
||||
|
||||
@ApiModelProperty(value = "手机号(APP登录)")
|
||||
private String phoneNumber;
|
||||
|
||||
@NotBlank
|
||||
@ApiModelProperty(value = "密码")
|
||||
private String password;
|
||||
|
||||
@ApiModelProperty(value = "验证码")
|
||||
private String code;
|
||||
|
||||
@ApiModelProperty(value = "验证码的key")
|
||||
private String uuid = "";
|
||||
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.security.service.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
|
||||
/**
|
||||
* 避免序列化问题
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-30
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class AuthorityDto implements GrantedAuthority {
|
||||
|
||||
@ApiModelProperty(value = "角色名")
|
||||
private String authority;
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.security.service.dto;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import com.fuyuanshen.modules.system.domain.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-23
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public class JwtUserDto implements UserDetails {
|
||||
|
||||
@ApiModelProperty(value = "用户")
|
||||
private final User user;
|
||||
|
||||
@ApiModelProperty(value = "数据权限")
|
||||
private final List<Long> dataScopes;
|
||||
|
||||
@ApiModelProperty(value = "角色")
|
||||
private final List<AuthorityDto> authorities;
|
||||
|
||||
public Set<String> getRoles() {
|
||||
return authorities.stream().map(AuthorityDto::getAuthority).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
@JSONField(serialize = false)
|
||||
public String getPassword() {
|
||||
return user.getPassword();
|
||||
}
|
||||
|
||||
@Override
|
||||
@JSONField(serialize = false)
|
||||
public String getUsername() {
|
||||
return user.getUsername();
|
||||
}
|
||||
|
||||
@JSONField(serialize = false)
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@JSONField(serialize = false)
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@JSONField(serialize = false)
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JSONField(serialize = false)
|
||||
public boolean isEnabled() {
|
||||
return user.getEnabled();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.security.service.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 在线用户
|
||||
* @author Zheng Jie
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class OnlineUserDto {
|
||||
|
||||
@ApiModelProperty(value = "Token编号")
|
||||
private String uid;
|
||||
|
||||
@ApiModelProperty(value = "用户名")
|
||||
private String userName;
|
||||
|
||||
@ApiModelProperty(value = "昵称")
|
||||
private String nickName;
|
||||
|
||||
@ApiModelProperty(value = "岗位")
|
||||
private String dept;
|
||||
|
||||
@ApiModelProperty(value = "浏览器")
|
||||
private String browser;
|
||||
|
||||
@ApiModelProperty(value = "IP")
|
||||
private String ip;
|
||||
|
||||
@ApiModelProperty(value = "地址")
|
||||
private String address;
|
||||
|
||||
@ApiModelProperty(value = "token")
|
||||
private String key;
|
||||
|
||||
@ApiModelProperty(value = "登录时间")
|
||||
private Date loginTime;
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.security.service.dto.app;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* @author Jimbo Gu
|
||||
* @date 2025-06-18
|
||||
*/
|
||||
@Data
|
||||
public class AppAuthUserQuery {
|
||||
|
||||
@ApiModelProperty(value = "用户名")
|
||||
private String username;
|
||||
|
||||
@NotBlank
|
||||
@ApiModelProperty(value = "手机号(APP登录)")
|
||||
private String phoneNumber;
|
||||
|
||||
@NotBlank
|
||||
@ApiModelProperty(value = "密码")
|
||||
private String password;
|
||||
|
||||
@ApiModelProperty(value = "验证码")
|
||||
private Integer VerificationCode;
|
||||
|
||||
/*@ApiModelProperty(value = "验证码")
|
||||
private String code;
|
||||
|
||||
@ApiModelProperty(value = "验证码的key")
|
||||
private String uuid = "";*/
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,43 @@
|
||||
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.security.service.dto.app;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author Jimbo Gu
|
||||
* @date 2025-06-18
|
||||
*/
|
||||
@Data
|
||||
public class AppRoleDto {
|
||||
|
||||
@ApiModelProperty(value = "级别名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(value = "级别")
|
||||
private Byte level;
|
||||
|
||||
@ApiModelProperty(value = "描述")
|
||||
private String description;
|
||||
|
||||
@ApiModelProperty(value = "权利范围")
|
||||
private String dataScope;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
package com.fuyuanshen.modules.system.constant;
|
||||
|
||||
/**
|
||||
* 用户相关常量定义
|
||||
*
|
||||
* @author: 默苍璃
|
||||
* @date: 2025-06-1011:13
|
||||
*/
|
||||
|
||||
public class UserConstants {
|
||||
|
||||
/**
|
||||
* 最大用户层级限制
|
||||
*/
|
||||
public static final int MAX_USER_LEVEL = 5;
|
||||
|
||||
/**
|
||||
* 用户层级超出限制时的提示信息
|
||||
*/
|
||||
public static final String USER_LEVEL_EXCEED_LIMIT_MESSAGE = "当前用户不允许再创建下级用户!";
|
||||
|
||||
|
||||
/**
|
||||
* 超级管理员用户 ID 默认值
|
||||
*/
|
||||
public static final Long SUPER_ADMIN_ID = 10000L;
|
||||
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
package com.fuyuanshen.modules.system.converter;
|
||||
|
||||
import com.alibaba.excel.converters.Converter;
|
||||
import com.alibaba.excel.enums.CellDataTypeEnum;
|
||||
import com.alibaba.excel.metadata.GlobalConfiguration;
|
||||
import com.alibaba.excel.metadata.data.WriteCellData;
|
||||
import com.alibaba.excel.metadata.property.ExcelContentProperty;
|
||||
import com.alibaba.excel.util.FileUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
|
||||
/**
|
||||
* @author: 默苍璃
|
||||
* @date: 2025-06-0618:56
|
||||
*/
|
||||
|
||||
public class IgnoreFailedImageConverter implements Converter<URL> {
|
||||
private static final Logger logger = LoggerFactory.getLogger(IgnoreFailedImageConverter.class);
|
||||
|
||||
@Override
|
||||
public Class<?> supportJavaTypeKey() {
|
||||
return URL.class;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public CellDataTypeEnum supportExcelTypeKey() {
|
||||
// return CellDataTypeEnum.STRING;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public WriteCellData<?> convertToExcelData(URL value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
URLConnection conn = value.openConnection();
|
||||
conn.setConnectTimeout(2000); // 2秒超时
|
||||
conn.setReadTimeout(3000); // 3秒超时
|
||||
|
||||
try (InputStream inputStream = conn.getInputStream()) {
|
||||
// byte[] bytes = FileUtils.readInputStream(inputStream, value.toString());
|
||||
// 替代 FileUtils.readInputStream 的自定义方法
|
||||
byte[] bytes = readInputStream(inputStream);
|
||||
return new WriteCellData<>(bytes);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 静默忽略错误,只记录日志
|
||||
logger.debug("忽略图片加载失败: {}, 原因: {}", value, e.getMessage());
|
||||
// return null; // 返回null表示不写入图片
|
||||
return new WriteCellData<>(new byte[0]); // 返回空数组而不是 null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 替代 FileUtils.readInputStream 的自定义方法
|
||||
*
|
||||
* @param inputStream 输入流
|
||||
* @return 字节数组
|
||||
* @throws Exception 读取异常
|
||||
*/
|
||||
private byte[] readInputStream(InputStream inputStream) throws Exception {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[8192];
|
||||
int bytesRead;
|
||||
|
||||
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||
outputStream.write(buffer, 0, bytesRead);
|
||||
}
|
||||
|
||||
return outputStream.toByteArray();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
// package com.fuyuanshen.modules.system.converter;
|
||||
//
|
||||
// import com.alibaba.excel.converters.Converter;
|
||||
// import com.alibaba.excel.enums.CellDataTypeEnum;
|
||||
// import com.alibaba.excel.metadata.GlobalConfiguration;
|
||||
// import com.alibaba.excel.metadata.data.ReadCellData;
|
||||
// import com.alibaba.excel.metadata.property.ExcelContentProperty;
|
||||
//
|
||||
// import java.io.ByteArrayOutputStream;
|
||||
// import java.io.IOException;
|
||||
//
|
||||
// /**
|
||||
// * @author: 默苍璃
|
||||
// * @date: 2025-06-0710:01
|
||||
// */
|
||||
//
|
||||
// public class ImageReadConverter implements Converter<byte[]> {
|
||||
//
|
||||
// @Override
|
||||
// public Class<?> supportJavaTypeKey() {
|
||||
// return byte[].class;
|
||||
// }
|
||||
//
|
||||
// // @Override
|
||||
// // public CellDataTypeEnum supportExcelTypeKey() {
|
||||
// // return CellDataTypeEnum.IMAGE;
|
||||
// // }
|
||||
//
|
||||
// @Override
|
||||
// public byte[] convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws IOException {
|
||||
// if (cellData.getType() == CellDataTypeEnum.IMAGE) {
|
||||
// ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
// cellData.getImageValueList().forEach(image -> {
|
||||
// try {
|
||||
// outputStream.write(image.getImageBytes());
|
||||
// } catch (IOException e) {
|
||||
// throw new RuntimeException(e);
|
||||
// }
|
||||
// });
|
||||
// return outputStream.toByteArray();
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
@ -0,0 +1,41 @@
|
||||
package com.fuyuanshen.modules.system.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import com.fuyuanshen.base.BaseEntity;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author: 默苍璃
|
||||
* @date: 2025-06-1308:57
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("customer_device")
|
||||
public class CustomerDevice extends BaseEntity implements Serializable {
|
||||
|
||||
@NotNull(groups = Update.class)
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
@TableField(value = "customer_id")
|
||||
private Long customerId;
|
||||
|
||||
@TableField(value = "device_id")
|
||||
private Long deviceId;
|
||||
|
||||
/**
|
||||
* 设备状态
|
||||
* 0 失效
|
||||
* 1 正常
|
||||
*/
|
||||
@TableField(value = "assign_status")
|
||||
private Byte assignStatus;
|
||||
|
||||
}
|
||||
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.system.domain;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import com.fuyuanshen.base.BaseEntity;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2019-03-25
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("sys_dept")
|
||||
public class Dept extends BaseEntity implements Serializable {
|
||||
|
||||
@NotNull(groups = Update.class)
|
||||
@TableId(value="dept_id", type = IdType.AUTO)
|
||||
@ApiModelProperty(value = "ID", hidden = true)
|
||||
private Long id;
|
||||
|
||||
@TableField(exist = false)
|
||||
@JSONField(serialize = false)
|
||||
@ApiModelProperty(value = "角色")
|
||||
private Set<Role> roles;
|
||||
|
||||
@TableField(exist = false)
|
||||
@ApiModelProperty(value = "子部门")
|
||||
private List<Dept> children;
|
||||
|
||||
@ApiModelProperty(value = "排序")
|
||||
private Integer deptSort;
|
||||
|
||||
@NotBlank
|
||||
@ApiModelProperty(value = "部门名称")
|
||||
private String name;
|
||||
|
||||
@NotNull
|
||||
@ApiModelProperty(value = "是否启用")
|
||||
private Boolean enabled;
|
||||
|
||||
@ApiModelProperty(value = "上级部门")
|
||||
private Long pid;
|
||||
|
||||
@ApiModelProperty(value = "子节点数目", hidden = true)
|
||||
private Integer subCount = 0;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Dept dept = (Dept) o;
|
||||
return Objects.equals(id, dept.id) &&
|
||||
Objects.equals(name, dept.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, name);
|
||||
}
|
||||
|
||||
@ApiModelProperty(value = "是否有子节点")
|
||||
public Boolean getHasChildren() {
|
||||
return subCount > 0;
|
||||
}
|
||||
|
||||
|
||||
@ApiModelProperty(value = "是否为叶子")
|
||||
public Boolean getLeaf() {
|
||||
return subCount <= 0;
|
||||
}
|
||||
|
||||
@ApiModelProperty(value = "标签名称")
|
||||
public String getLabel() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,93 @@
|
||||
package com.fuyuanshen.modules.system.domain;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.bean.copier.CopyOptions;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import com.fuyuanshen.base.BaseEntity;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @Description: 设备表
|
||||
* @Author: WY
|
||||
* @Date: 2025/5/16
|
||||
**/
|
||||
@Data
|
||||
@TableName("device")
|
||||
public class Device extends BaseEntity implements Serializable {
|
||||
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
@ApiModelProperty(value = "ID")
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty(value = "设备类型")
|
||||
private Long deviceType;
|
||||
|
||||
@ApiModelProperty(value = "客户号")
|
||||
private Long customerId;
|
||||
|
||||
@ApiModelProperty(value = "所属客户")
|
||||
private String customerName;
|
||||
|
||||
/*@ApiModelProperty(value = "设备编号")
|
||||
private String deviceNo;*/
|
||||
|
||||
@ApiModelProperty(value = "设备名称")
|
||||
private String deviceName;
|
||||
|
||||
@ApiModelProperty(value = "设备图片")
|
||||
private String devicePic;
|
||||
|
||||
@ApiModelProperty(value = "设备MAC")
|
||||
private String deviceMac;
|
||||
|
||||
@ApiModelProperty(value = "设备SN")
|
||||
private String deviceSn;
|
||||
|
||||
@ApiModelProperty(value = "经度")
|
||||
private String longitude;
|
||||
|
||||
@ApiModelProperty(value = "纬度")
|
||||
private String latitude;
|
||||
|
||||
@ApiModelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
||||
@TableField(exist = false)
|
||||
@ApiModelProperty(value = "设备类型名称")
|
||||
private String typeName;
|
||||
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
@TableField(value = "tenant_id")
|
||||
@ApiModelProperty(hidden = true)
|
||||
private Long tenantId;
|
||||
|
||||
/**
|
||||
* 设备状态
|
||||
* 0 失效
|
||||
* 1 正常
|
||||
*/
|
||||
@ApiModelProperty(value = "设备状态")
|
||||
private Integer deviceStatus;
|
||||
|
||||
/**
|
||||
* 绑定状态
|
||||
* 0 未绑定
|
||||
* 1 已绑定
|
||||
*/
|
||||
@ApiModelProperty(value = "绑定状态")
|
||||
private Integer bindingStatus;
|
||||
|
||||
|
||||
public void copy(Device source) {
|
||||
BeanUtil.copyProperties(source, this, CopyOptions.create().setIgnoreNullValue(true));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
package com.fuyuanshen.modules.system.domain;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.bean.copier.CopyOptions;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import com.fuyuanshen.base.BaseEntity;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @Description:
|
||||
* @Author: WY
|
||||
* @Date: 2025/5/24
|
||||
**/
|
||||
@Data
|
||||
@TableName("device_log")
|
||||
public class DeviceLog extends BaseEntity implements Serializable {
|
||||
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
@ApiModelProperty(value = "ID")
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty(value = "设备行为")
|
||||
private String deviceAction;
|
||||
|
||||
@ApiModelProperty(value = "设备名称")
|
||||
private String deviceName;
|
||||
|
||||
@ApiModelProperty(value = "数据来源")
|
||||
private String dataSource;
|
||||
|
||||
@ApiModelProperty(value = "内容")
|
||||
private String content;
|
||||
|
||||
public void copy(DeviceLog source){
|
||||
BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
package com.fuyuanshen.modules.system.domain;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.bean.copier.CopyOptions;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import com.fuyuanshen.base.BaseEntity;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.io.Serializable;
|
||||
import java.sql.Timestamp;
|
||||
|
||||
/**
|
||||
* @Description: 设备类型
|
||||
* @Author: WY
|
||||
* @Date: 2025/5/14
|
||||
**/
|
||||
@Data
|
||||
@TableName("device_type")
|
||||
public class DeviceType extends BaseEntity implements Serializable {
|
||||
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
@ApiModelProperty(value = "ID", hidden = true)
|
||||
private Long id;
|
||||
|
||||
@ExcelProperty("客户号")
|
||||
private Long customerId;
|
||||
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
// @TableField(value = "tenant_id")
|
||||
// @ApiModelProperty(hidden = true)
|
||||
// private Long tenantId;
|
||||
|
||||
@NotBlank(message = "设备类型名称不能为空")
|
||||
@ApiModelProperty(value = "类型名称", required = true)
|
||||
private String typeName;
|
||||
|
||||
@ApiModelProperty(value = "是否支持蓝牙")
|
||||
private Boolean isSupportBle;
|
||||
|
||||
@ApiModelProperty(value = "定位方式", example = "0:无;1:GPS;2:基站;3:wifi;4:北斗")
|
||||
private String locateMode;
|
||||
|
||||
@ApiModelProperty(value = "联网方式", example = "0:无;1:4G;2:WIFI")
|
||||
private String networkWay;
|
||||
|
||||
@ApiModelProperty(value = "通讯方式", example = "0:4G;1:蓝牙")
|
||||
private String communicationMode;
|
||||
|
||||
public void copy(DeviceType source) {
|
||||
BeanUtil.copyProperties(source, this, CopyOptions.create().setIgnoreNullValue(true));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.system.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import com.fuyuanshen.base.BaseEntity;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2019-04-10
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("sys_dict")
|
||||
public class Dict extends BaseEntity implements Serializable {
|
||||
|
||||
@NotNull(groups = Update.class)
|
||||
@ApiModelProperty(value = "ID", hidden = true)
|
||||
@TableId(value = "dict_id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
@NotBlank
|
||||
@ApiModelProperty(value = "名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(value = "描述")
|
||||
private String description;
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.system.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import com.fuyuanshen.base.BaseEntity;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2019-04-10
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("sys_dict_detail")
|
||||
public class DictDetail extends BaseEntity implements Serializable {
|
||||
|
||||
@NotNull(groups = Update.class)
|
||||
@ApiModelProperty(value = "ID", hidden = true)
|
||||
@TableId(value = "detail_id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
@TableField(value = "dict_id")
|
||||
@ApiModelProperty(hidden = true)
|
||||
private Long dictId;
|
||||
|
||||
@TableField(exist = false)
|
||||
@ApiModelProperty(value = "字典")
|
||||
private Dict dict;
|
||||
|
||||
@ApiModelProperty(value = "字典标签")
|
||||
private String label;
|
||||
|
||||
@ApiModelProperty(value = "字典值")
|
||||
private String value;
|
||||
|
||||
@ApiModelProperty(value = "排序")
|
||||
private Integer dictSort = 999;
|
||||
}
|
||||
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.system.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import com.fuyuanshen.base.BaseEntity;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2019-03-29
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("sys_job")
|
||||
public class Job extends BaseEntity implements Serializable {
|
||||
|
||||
@NotNull(groups = Update.class)
|
||||
@TableId(value="job_id", type = IdType.AUTO)
|
||||
@ApiModelProperty(value = "ID", hidden = true)
|
||||
private Long id;
|
||||
|
||||
@NotBlank
|
||||
@ApiModelProperty(value = "岗位名称")
|
||||
private String name;
|
||||
|
||||
@NotNull
|
||||
@ApiModelProperty(value = "岗位排序")
|
||||
private Long jobSort;
|
||||
|
||||
@NotNull
|
||||
@ApiModelProperty(value = "是否启用")
|
||||
private Boolean enabled;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Job job = (Job) o;
|
||||
return Objects.equals(id, job.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.system.domain;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import com.fuyuanshen.base.BaseEntity;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2018-12-17
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("sys_menu")
|
||||
public class Menu extends BaseEntity implements Serializable {
|
||||
|
||||
@NotNull(groups = {Update.class})
|
||||
@TableId(value="menu_id", type = IdType.AUTO)
|
||||
@ApiModelProperty(value = "ID", hidden = true)
|
||||
private Long id;
|
||||
|
||||
@TableField(exist = false)
|
||||
@JSONField(serialize = false)
|
||||
@ApiModelProperty(value = "菜单角色")
|
||||
private Set<Role> roles;
|
||||
|
||||
@TableField(exist = false)
|
||||
private List<Menu> children;
|
||||
|
||||
@ApiModelProperty(value = "菜单标题")
|
||||
private String title;
|
||||
|
||||
@TableField(value = "name")
|
||||
@ApiModelProperty(value = "菜单组件名称")
|
||||
private String componentName;
|
||||
|
||||
@ApiModelProperty(value = "排序")
|
||||
private Integer menuSort = 999;
|
||||
|
||||
@ApiModelProperty(value = "组件路径")
|
||||
private String component;
|
||||
|
||||
@ApiModelProperty(value = "路由地址")
|
||||
private String path;
|
||||
|
||||
@ApiModelProperty(value = "菜单类型,目录、菜单、按钮")
|
||||
private Integer type;
|
||||
|
||||
@ApiModelProperty(value = "权限标识")
|
||||
private String permission;
|
||||
|
||||
@ApiModelProperty(value = "菜单图标")
|
||||
private String icon;
|
||||
|
||||
@ApiModelProperty(value = "缓存")
|
||||
private Boolean cache;
|
||||
|
||||
@ApiModelProperty(value = "是否隐藏")
|
||||
private Boolean hidden;
|
||||
|
||||
@ApiModelProperty(value = "上级菜单")
|
||||
private Long pid;
|
||||
|
||||
@ApiModelProperty(value = "子节点数目", hidden = true)
|
||||
private Integer subCount = 0;
|
||||
|
||||
@ApiModelProperty(value = "外链菜单")
|
||||
private Boolean iFrame;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Menu menu = (Menu) o;
|
||||
return Objects.equals(id, menu.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id);
|
||||
}
|
||||
|
||||
@ApiModelProperty(value = "是否有子节点")
|
||||
public Boolean getHasChildren() {
|
||||
return subCount > 0;
|
||||
}
|
||||
|
||||
@ApiModelProperty(value = "是否为叶子")
|
||||
public Boolean getLeaf() {
|
||||
return subCount <= 0;
|
||||
}
|
||||
|
||||
@ApiModelProperty(value = "标签名称")
|
||||
public String getLabel() {
|
||||
return title;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.system.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import com.fuyuanshen.base.BaseEntity;
|
||||
import com.fuyuanshen.utils.enums.DataScopeEnum;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 角色
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-22
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("sys_role")
|
||||
public class Role extends BaseEntity implements Serializable {
|
||||
|
||||
@NotNull(groups = {Update.class})
|
||||
@TableId(value="role_id", type = IdType.AUTO)
|
||||
@ApiModelProperty(value = "ID", hidden = true)
|
||||
private Long id;
|
||||
|
||||
@TableField(exist = false)
|
||||
@ApiModelProperty(value = "用户", hidden = true)
|
||||
private Set<User> users;
|
||||
|
||||
@TableField(exist = false)
|
||||
@ApiModelProperty(value = "菜单", hidden = true)
|
||||
private Set<Menu> menus;
|
||||
|
||||
@TableField(exist = false)
|
||||
@ApiModelProperty(value = "部门", hidden = true)
|
||||
private Set<Dept> depts;
|
||||
|
||||
@NotBlank
|
||||
@ApiModelProperty(value = "名称", hidden = true)
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(value = "数据权限,全部 、 本级 、 自定义")
|
||||
private String dataScope = DataScopeEnum.THIS_LEVEL.getValue();
|
||||
|
||||
@ApiModelProperty(value = "级别,数值越小,级别越大")
|
||||
private Integer level = 3;
|
||||
|
||||
@ApiModelProperty(value = "描述")
|
||||
private String description;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Role role = (Role) o;
|
||||
return Objects.equals(id, role.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.system.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import com.fuyuanshen.base.BaseEntity;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-22
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("sys_user")
|
||||
public class User extends BaseEntity implements Serializable {
|
||||
|
||||
@NotNull(groups = Update.class)
|
||||
@TableId(value = "user_id", type = IdType.AUTO)
|
||||
@ApiModelProperty(value = "ID", hidden = true)
|
||||
private Long id;
|
||||
|
||||
@TableField(exist = false)
|
||||
@ApiModelProperty(value = "用户角色")
|
||||
private Set<Role> roles;
|
||||
|
||||
@TableField(exist = false)
|
||||
@ApiModelProperty(value = "用户岗位")
|
||||
private Set<Job> jobs;
|
||||
|
||||
@TableField(value = "dept_id")
|
||||
@ApiModelProperty(hidden = true)
|
||||
private Long deptId;
|
||||
|
||||
@ApiModelProperty(hidden = true)
|
||||
private Long pid;
|
||||
|
||||
@TableField(value = "user_level")
|
||||
@ApiModelProperty(hidden = true)
|
||||
private Byte userLevel;
|
||||
|
||||
@ApiModelProperty(value = "用户部门")
|
||||
@TableField(exist = false)
|
||||
private Dept dept;
|
||||
|
||||
@NotBlank
|
||||
@ApiModelProperty(value = "账号")
|
||||
private String username;
|
||||
|
||||
// @NotBlank
|
||||
@ApiModelProperty(value = "用户昵称")
|
||||
private String nickName;
|
||||
|
||||
@Email
|
||||
// @NotBlank
|
||||
@ApiModelProperty(value = "邮箱")
|
||||
private String email;
|
||||
|
||||
// @NotBlank
|
||||
@ApiModelProperty(value = "电话号码")
|
||||
private Long phone;
|
||||
|
||||
@ApiModelProperty(value = "用户性别")
|
||||
private String gender;
|
||||
|
||||
@ApiModelProperty(value = "头像真实名称", hidden = true)
|
||||
private String avatarName;
|
||||
|
||||
@ApiModelProperty(value = "头像存储的路径", hidden = true)
|
||||
private String avatarPath;
|
||||
|
||||
@ApiModelProperty(value = "密码")
|
||||
private String password;
|
||||
|
||||
@NotNull
|
||||
@ApiModelProperty(value = "是否启用")
|
||||
private Boolean enabled;
|
||||
|
||||
/**
|
||||
* 是否为admin账号
|
||||
* 0否
|
||||
* 1是
|
||||
*/
|
||||
@ApiModelProperty(value = "是否为admin账号", hidden = true)
|
||||
@TableField(value = "is_admin")
|
||||
private Byte admin;
|
||||
|
||||
@TableField(exist = false)
|
||||
private Boolean isAdmin = false;
|
||||
|
||||
@ApiModelProperty(value = "最后修改密码的时间", hidden = true)
|
||||
private Date pwdResetTime;
|
||||
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
@TableField(value = "tenant_id")
|
||||
@ApiModelProperty(hidden = true)
|
||||
private Long tenantId;
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
User user = (User) o;
|
||||
return Objects.equals(id, user.id) && Objects.equals(username, user.username);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, username);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,100 @@
|
||||
package com.fuyuanshen.modules.system.domain.app;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.bean.copier.CopyOptions;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fuyuanshen.base.BaseEntity;
|
||||
import com.fuyuanshen.modules.system.domain.Device;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @Description: 设备表
|
||||
* @Author: WY
|
||||
* @Date: 2025/5/16
|
||||
**/
|
||||
@Data
|
||||
@TableName("app_device")
|
||||
public class APPDevice extends BaseEntity implements Serializable {
|
||||
|
||||
@TableId(value = "app_device_id", type = IdType.AUTO)
|
||||
@ApiModelProperty(value = "ID")
|
||||
private Long id;
|
||||
|
||||
|
||||
@ApiModelProperty(value = "设备类型")
|
||||
private Long deviceType;
|
||||
|
||||
@ApiModelProperty(value = "设备类型名称")
|
||||
private String deviceTypeName;
|
||||
|
||||
@ApiModelProperty(value = "客户号")
|
||||
private Long customerId;
|
||||
|
||||
@ApiModelProperty(value = "所属客户")
|
||||
private String customerName;
|
||||
|
||||
/*@ApiModelProperty(value = "设备编号")
|
||||
private String deviceNo;*/
|
||||
|
||||
@ApiModelProperty(value = "设备名称")
|
||||
private String deviceName;
|
||||
|
||||
@ApiModelProperty(value = "设备图片")
|
||||
private String devicePic;
|
||||
|
||||
@ApiModelProperty(value = "设备MAC")
|
||||
private String deviceMac;
|
||||
|
||||
@ApiModelProperty(value = "设备SN")
|
||||
private String deviceSn;
|
||||
|
||||
@ApiModelProperty(value = "经度")
|
||||
private String longitude;
|
||||
|
||||
@ApiModelProperty(value = "纬度")
|
||||
private String latitude;
|
||||
|
||||
@ApiModelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
||||
@TableField(exist = false)
|
||||
@ApiModelProperty(value = "设备类型名称")
|
||||
private String typeName;
|
||||
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
@TableField(value = "tenant_id")
|
||||
@ApiModelProperty(hidden = true)
|
||||
private Long tenantId;
|
||||
|
||||
/**
|
||||
* 设备状态
|
||||
* 0 失效
|
||||
* 1 正常
|
||||
*/
|
||||
@ApiModelProperty(value = "设备状态")
|
||||
private Integer deviceStatus;
|
||||
|
||||
/**
|
||||
* 绑定状态
|
||||
* 0 未绑定
|
||||
* 1 已绑定
|
||||
*/
|
||||
@ApiModelProperty(value = "绑定状态")
|
||||
private Integer bindingStatus;
|
||||
|
||||
|
||||
public void copy(Device source) {
|
||||
BeanUtil.copyProperties(source, this, CopyOptions.create().setIgnoreNullValue(true));
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
package com.fuyuanshen.modules.system.domain.app;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fuyuanshen.modules.system.domain.DeviceType;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Description: 设备类型
|
||||
* @Author: WY
|
||||
* @Date: 2025/5/14
|
||||
**/
|
||||
@Data
|
||||
@TableName("app_device_type")
|
||||
public class APPDeviceType extends DeviceType {
|
||||
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
@ApiModelProperty(value = "ID", hidden = true)
|
||||
private Long id;
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.system.domain.app;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fuyuanshen.base.BaseEntity;
|
||||
import com.fuyuanshen.modules.system.domain.Role;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2018-12-17
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("app_sys_menu")
|
||||
public class APPMenu extends BaseEntity implements Serializable {
|
||||
|
||||
@NotNull(groups = {Update.class})
|
||||
@TableId(value="menu_id", type = IdType.AUTO)
|
||||
@ApiModelProperty(value = "ID", hidden = true)
|
||||
private Long id;
|
||||
|
||||
@TableField(exist = false)
|
||||
@JSONField(serialize = false)
|
||||
@ApiModelProperty(value = "菜单角色")
|
||||
private Set<Role> roles;
|
||||
|
||||
@TableField(exist = false)
|
||||
private List<APPMenu> children;
|
||||
|
||||
@ApiModelProperty(value = "菜单标题")
|
||||
private String title;
|
||||
|
||||
@TableField(value = "name")
|
||||
@ApiModelProperty(value = "菜单组件名称")
|
||||
private String componentName;
|
||||
|
||||
@ApiModelProperty(value = "排序")
|
||||
private Integer menuSort = 999;
|
||||
|
||||
@ApiModelProperty(value = "组件路径")
|
||||
private String component;
|
||||
|
||||
@ApiModelProperty(value = "路由地址")
|
||||
private String path;
|
||||
|
||||
@ApiModelProperty(value = "菜单类型,目录、菜单、按钮")
|
||||
private Integer type;
|
||||
|
||||
@ApiModelProperty(value = "权限标识")
|
||||
private String permission;
|
||||
|
||||
@ApiModelProperty(value = "菜单图标")
|
||||
private String icon;
|
||||
|
||||
@ApiModelProperty(value = "缓存")
|
||||
private Boolean cache;
|
||||
|
||||
@ApiModelProperty(value = "是否隐藏")
|
||||
private Boolean hidden;
|
||||
|
||||
@ApiModelProperty(value = "上级菜单")
|
||||
private Long pid;
|
||||
|
||||
@ApiModelProperty(value = "子节点数目", hidden = true)
|
||||
private Integer subCount = 0;
|
||||
|
||||
@ApiModelProperty(value = "外链菜单")
|
||||
private Boolean iFrame;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
APPMenu menu = (APPMenu) o;
|
||||
return Objects.equals(id, menu.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id);
|
||||
}
|
||||
|
||||
@ApiModelProperty(value = "是否有子节点")
|
||||
public Boolean getHasChildren() {
|
||||
return subCount > 0;
|
||||
}
|
||||
|
||||
@ApiModelProperty(value = "是否为叶子")
|
||||
public Boolean getLeaf() {
|
||||
return subCount <= 0;
|
||||
}
|
||||
|
||||
@ApiModelProperty(value = "标签名称")
|
||||
public String getLabel() {
|
||||
return title;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.system.domain.app;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fuyuanshen.modules.system.domain.Role;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 角色
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-22
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("app_sys_role")
|
||||
public class APPRole extends Role {
|
||||
|
||||
@NotNull(groups = {Update.class})
|
||||
@TableId(value="app_role_id", type = IdType.AUTO)
|
||||
@ApiModelProperty(value = "ID", hidden = true)
|
||||
private Long id;
|
||||
|
||||
}
|
||||
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.system.domain.app;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fuyuanshen.base.BaseEntity;
|
||||
import com.fuyuanshen.modules.system.domain.Dept;
|
||||
import com.fuyuanshen.modules.system.domain.Job;
|
||||
import com.fuyuanshen.modules.system.domain.Role;
|
||||
import com.fuyuanshen.modules.system.domain.User;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-22
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("app_user")
|
||||
public class APPUser extends BaseEntity implements Serializable {
|
||||
|
||||
@NotNull(groups = Update.class)
|
||||
@TableId(value = "app_user_id", type = IdType.AUTO)
|
||||
@ApiModelProperty(value = "ID", hidden = true)
|
||||
private Long id;
|
||||
|
||||
@TableField(value = "dept_id")
|
||||
@ApiModelProperty(hidden = true)
|
||||
private Long deptId;
|
||||
|
||||
@ApiModelProperty(hidden = true)
|
||||
private Long pid;
|
||||
|
||||
@TableField(value = "user_level")
|
||||
@ApiModelProperty(hidden = true)
|
||||
private Byte userLevel;
|
||||
|
||||
@ApiModelProperty(value = "用户部门")
|
||||
@TableField(exist = false)
|
||||
private Dept dept;
|
||||
|
||||
@NotBlank
|
||||
@ApiModelProperty(value = "账号")
|
||||
private String username;
|
||||
|
||||
// @NotBlank
|
||||
@ApiModelProperty(value = "用户昵称")
|
||||
private String nickName;
|
||||
|
||||
@Email
|
||||
// @NotBlank
|
||||
@ApiModelProperty(value = "邮箱")
|
||||
private String email;
|
||||
|
||||
// @NotBlank
|
||||
@ApiModelProperty(value = "电话号码")
|
||||
private Long phone;
|
||||
|
||||
@ApiModelProperty(value = "用户性别")
|
||||
private String gender;
|
||||
|
||||
@ApiModelProperty(value = "头像真实名称", hidden = true)
|
||||
private String avatarName;
|
||||
|
||||
@ApiModelProperty(value = "头像存储的路径", hidden = true)
|
||||
private String avatarPath;
|
||||
|
||||
@ApiModelProperty(value = "密码")
|
||||
private String password;
|
||||
|
||||
@NotNull
|
||||
@ApiModelProperty(value = "是否启用")
|
||||
private Boolean enabled;
|
||||
|
||||
/**
|
||||
* 是否为admin账号
|
||||
* 0否
|
||||
* 1是
|
||||
*/
|
||||
@ApiModelProperty(value = "是否为admin账号", hidden = true)
|
||||
@TableField(value = "is_admin")
|
||||
private Byte admin;
|
||||
|
||||
@TableField(exist = false)
|
||||
private Boolean isAdmin = false;
|
||||
|
||||
@ApiModelProperty(value = "最后修改密码的时间", hidden = true)
|
||||
private Date pwdResetTime;
|
||||
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
@TableField(value = "tenant_id")
|
||||
@ApiModelProperty(hidden = true)
|
||||
private Long tenantId;
|
||||
|
||||
|
||||
/**
|
||||
* 用户类型
|
||||
* 0 app
|
||||
* 1 小程序
|
||||
*/
|
||||
@TableField(value = "user_type")
|
||||
@ApiModelProperty(hidden = true)
|
||||
private Integer userType;
|
||||
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
package com.fuyuanshen.modules.system.domain.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Description: 分配客户的Vo类
|
||||
* @Author: WY
|
||||
* @Date: 2025/5/28
|
||||
**/
|
||||
@Data
|
||||
public class CustomerVo {
|
||||
|
||||
@ApiModelProperty(value = "客户ID")
|
||||
private Long customerId;
|
||||
|
||||
@ApiModelProperty(value = "设备ID")
|
||||
private List<Long> deviceIds;
|
||||
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2019-2025 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.fuyuanshen.modules.system.domain.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2019-03-25
|
||||
*/
|
||||
@Data
|
||||
public class DeptQueryCriteria{
|
||||
|
||||
@ApiModelProperty(value = "部门id集合")
|
||||
private List<Long> ids;
|
||||
|
||||
@ApiModelProperty(value = "部门名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(value = "是否启用")
|
||||
private Boolean enabled;
|
||||
|
||||
@ApiModelProperty(value = "上级部门")
|
||||
private Long pid;
|
||||
|
||||
@ApiModelProperty(value = "PID为空查询")
|
||||
private Boolean pidIsNull;
|
||||
|
||||
@ApiModelProperty(value = "创建时间")
|
||||
private List<Timestamp> createTime;
|
||||
}
|
||||
@ -0,0 +1,84 @@
|
||||
package com.fuyuanshen.modules.system.domain.dto;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.alibaba.excel.annotation.write.style.ColumnWidth;
|
||||
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
|
||||
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import com.fuyuanshen.modules.system.converter.IgnoreFailedImageConverter;
|
||||
import org.springframework.data.annotation.CreatedBy;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* @author: 默苍璃
|
||||
* @date: 2025-06-0618:16
|
||||
*/
|
||||
@Data
|
||||
@HeadRowHeight(20) // 表头行高
|
||||
@ContentRowHeight(100) // 内容行高
|
||||
public class DeviceExcelExportDTO {
|
||||
|
||||
@ExcelProperty("ID")
|
||||
private Long id;
|
||||
|
||||
@ExcelProperty("设备类型")
|
||||
private Long deviceType;
|
||||
|
||||
// @ExcelProperty("客户号")
|
||||
// private Long customerId;
|
||||
|
||||
@ExcelProperty("所属客户")
|
||||
private String customerName;
|
||||
|
||||
@ExcelProperty("设备名称")
|
||||
@ColumnWidth(20)
|
||||
private String deviceName;
|
||||
|
||||
@ExcelProperty(value = "设备图片", converter = IgnoreFailedImageConverter.class)
|
||||
@ColumnWidth(15) // 设置图片列宽度
|
||||
private URL devicePic; // 使用URL类型
|
||||
|
||||
@ExcelProperty("设备MAC")
|
||||
@ColumnWidth(20)
|
||||
private String deviceMac;
|
||||
|
||||
@ExcelProperty("设备SN")
|
||||
@ColumnWidth(20)
|
||||
private String deviceSn;
|
||||
|
||||
@ExcelProperty("经度")
|
||||
private String longitude;
|
||||
|
||||
@ExcelProperty("纬度")
|
||||
private String latitude;
|
||||
|
||||
@ExcelProperty("备注")
|
||||
@ColumnWidth(30)
|
||||
private String remark;
|
||||
|
||||
@ExcelProperty("设备类型名称")
|
||||
@ColumnWidth(20)
|
||||
private String typeName;
|
||||
|
||||
/**
|
||||
* 设备状态
|
||||
* 0 失效
|
||||
* 1 正常
|
||||
*/
|
||||
@ExcelProperty("设备状态")
|
||||
@ColumnWidth(20)
|
||||
private String deviceStatus;
|
||||
|
||||
@ExcelProperty("创建时间")
|
||||
@ColumnWidth(20)
|
||||
private String createTime;
|
||||
|
||||
@ExcelProperty("创建人")
|
||||
@ColumnWidth(20)
|
||||
private String createBy;
|
||||
|
||||
}
|
||||
@ -0,0 +1,65 @@
|
||||
package com.fuyuanshen.modules.system.domain.dto;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.alibaba.excel.annotation.write.style.ColumnWidth;
|
||||
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
|
||||
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
|
||||
import com.alibaba.excel.converters.bytearray.ByteArrayImageConverter;
|
||||
import lombok.Data;
|
||||
import com.fuyuanshen.modules.system.converter.IgnoreFailedImageConverter;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* @author: 默苍璃
|
||||
* @date: 2025-06-0710:00
|
||||
*/
|
||||
@Data
|
||||
@HeadRowHeight(20) // 表头行高
|
||||
@ContentRowHeight(100) // 内容行高
|
||||
public class DeviceExcelImportDTO {
|
||||
|
||||
@ExcelProperty("设备类型")
|
||||
private Long deviceType;
|
||||
|
||||
@ExcelProperty("客户号")
|
||||
private Long customerId;
|
||||
|
||||
@ExcelProperty("设备名称")
|
||||
@ColumnWidth(20)
|
||||
private String deviceName;
|
||||
|
||||
|
||||
@ExcelProperty(value = "设备图片", converter = ByteArrayImageConverter.class)
|
||||
@ColumnWidth(15)
|
||||
private byte[] devicePic;
|
||||
|
||||
// 添加图片写入方法
|
||||
public void setDevicePicFromBytes(byte[] bytes) {
|
||||
this.devicePic = bytes;
|
||||
}
|
||||
|
||||
@ExcelProperty("设备MAC")
|
||||
@ColumnWidth(20)
|
||||
private String deviceMac;
|
||||
|
||||
@ExcelProperty("设备SN")
|
||||
@ColumnWidth(20)
|
||||
private String deviceSn;
|
||||
|
||||
@ExcelProperty("经度")
|
||||
private String longitude;
|
||||
|
||||
@ExcelProperty("纬度")
|
||||
private String latitude;
|
||||
|
||||
@ExcelProperty("备注")
|
||||
@ColumnWidth(30)
|
||||
private String remark;
|
||||
|
||||
@ExcelProperty("设备类型名称")
|
||||
@ColumnWidth(20)
|
||||
private String typeName;
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
package com.fuyuanshen.modules.system.domain.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* @Description: 设备表单
|
||||
* @Author: WY
|
||||
* @Date: 2025/5/17
|
||||
**/
|
||||
@Data
|
||||
public class DeviceForm {
|
||||
|
||||
@ApiModelProperty(value = "ID", hidden = true)
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty(value = "设备类型")
|
||||
private Long deviceType;
|
||||
|
||||
@ApiModelProperty(value = "客户号")
|
||||
private Long customerId;
|
||||
|
||||
/*@ApiModelProperty(value = "设备编号")
|
||||
private String deviceNo;*/
|
||||
|
||||
@NotBlank(message = "设备名称不能为空")
|
||||
@ApiModelProperty(value = "设备名称", required = true)
|
||||
private String deviceName;
|
||||
|
||||
@ApiModelProperty(value = "设备图片存储路径", hidden = true)
|
||||
private String devicePic;
|
||||
|
||||
@NotBlank(message = "设备MAC不能为空")
|
||||
@ApiModelProperty(value = "设备MAC", required = true)
|
||||
private String deviceMac;
|
||||
|
||||
@NotBlank(message = "设备SN不能为空")
|
||||
@ApiModelProperty(value = "设备SN", required = true)
|
||||
private String deviceSn;
|
||||
|
||||
@ApiModelProperty(value = "设备图片")
|
||||
private MultipartFile file;
|
||||
|
||||
@ApiModelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
package com.fuyuanshen.modules.system.domain.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Description:
|
||||
* @Author: WY
|
||||
* @Date: 2025/5/24
|
||||
**/
|
||||
@Data
|
||||
public class DeviceLogQueryCriteria {
|
||||
|
||||
@ApiModelProperty(value = "页码", example = "1")
|
||||
private Integer page = 1;
|
||||
|
||||
@ApiModelProperty(value = "每页数据量", example = "10")
|
||||
private Integer size = 10;
|
||||
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
package com.fuyuanshen.modules.system.domain.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @Description:
|
||||
* @Author: WY
|
||||
* @Date: 2025/5/16
|
||||
**/
|
||||
@Data
|
||||
public class DeviceQueryCriteria {
|
||||
|
||||
@ApiModelProperty(value = "设备名称")
|
||||
private String deviceName;
|
||||
|
||||
@ApiModelProperty(value = "设备类型")
|
||||
private Long deviceType;
|
||||
|
||||
@ApiModelProperty(value = "设备MAC")
|
||||
private String deviceMac;
|
||||
|
||||
@ApiModelProperty(value = "设备SN")
|
||||
private String deviceSn;
|
||||
|
||||
/**
|
||||
* 设备状态
|
||||
* 0 失效
|
||||
* 1 正常
|
||||
*/
|
||||
@ApiModelProperty(value = "设备状态 0 失效 1 正常 ")
|
||||
private Integer deviceStatus;
|
||||
|
||||
@ApiModelProperty(value = "创建时间")
|
||||
private List<Timestamp> createTime;
|
||||
|
||||
@ApiModelProperty(value = "页码", example = "1")
|
||||
private Integer page = 1;
|
||||
|
||||
@ApiModelProperty(value = "每页数据量", example = "10")
|
||||
private Integer size = 10;
|
||||
|
||||
@ApiModelProperty(value = "客户id")
|
||||
private Long customerId;
|
||||
private Set<Long> customerIds;
|
||||
|
||||
@ApiModelProperty(value = "租户ID")
|
||||
private Long tenantId;
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user