Commit 7f1d964c by 陈皓

init

parents
HELP.md
.gradle
/build/
/logs/
**/build/
**/out/
**/logs/
!gradle/wrapper/gradle-wrapper.jar
*.log
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
/out/
**/target/
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
# cloud-backend
接口改过, 需要配合改版的前端页面 前端页面地址: http://139.159.239.83:9093/framework/front-backend.git
需要什么工具类common-utils中没有的可以先看下hutool文档, 提供了大量工具
https://www.hutool.cn/
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>image-backend</artifactId>
<groupId>com.zq</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>admin-server</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<!-- oshi监控需要指定jna版本, 问题详见 https://github.com/oshi/oshi/issues/1040 -->
<jna.version>5.8.0</jna.version>
<mapstruct.version>1.5.5.Final</mapstruct.version>
<alipay.version>4.9.153.ALL</alipay.version>
<qiniu.version>[7.2.0, 7.2.99]</qiniu.version>
<configuration.version>1.9</configuration.version>
</properties>
<dependencies>
<dependency>
<groupId>com.zq</groupId>
<artifactId>img-common-utils</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.zq</groupId>
<artifactId>logging-server</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--Spring boot 核心-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- Spring boot websocket -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!-- generator模块依赖-模板引擎-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-- generator模块依赖- https://mvnrepository.com/artifact/commons-configuration/commons-configuration -->
<dependency>
<groupId>commons-configuration</groupId>
<artifactId>commons-configuration</artifactId>
<version>${configuration.version}</version>
</dependency>
<!--数据库相关-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis.plus.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${alibaba.druid.version}</version>
</dependency>
<!-- quartz -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
</dependency>
<!--JWT相关-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jjwt.version}</version>
</dependency>
<!--支付宝依赖-->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>${alipay.version}</version>
</dependency>
<!--七牛云存储-->
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>qiniu-java-sdk</artifactId>
<version>${qiniu.version}</version>
</dependency>
<!-- 必须放在mapstruct依赖前面 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--mapStruct依赖-->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<!-- Java图形验证码 -->
<dependency>
<groupId>com.github.whvcse</groupId>
<artifactId>easy-captcha</artifactId>
<version>1.6.2</version>
</dependency>
<!-- linux的管理 -->
<dependency>
<groupId>ch.ethz.ganymed</groupId>
<artifactId>ganymed-ssh2</artifactId>
<version>build210</version>
</dependency>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.55</version>
</dependency>
<!-- 获取系统信息 -->
<dependency>
<groupId>com.github.oshi</groupId>
<artifactId>oshi-core</artifactId>
<version>5.7.1</version>
</dependency>
<!-- excel工具 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>xerces</groupId>
<artifactId>xercesImpl</artifactId>
<version>2.12.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- 打包时跳过测试 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
<!-- 使用@profiles.active@需要添加以下内容 -->
<resources>
<resource>
<directory>src/main/resources</directory>
<!--开启过滤,用指定的参数替换directory下的文件中的参数-->
<filtering>true</filtering>
</resource>
</resources>
</build>
</project>
package com.zq.admin;
import com.zq.common.annotation.rest.AnonymousGetMapping;
import io.swagger.annotations.Api;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.bind.annotation.RestController;
/**
* 开启审计功能 -> @EnableJpaAuditing
*
* @author Zheng Jie
* @date 2018/11/15 9:20:19
*/
@Api(hidden = true)
@EnableAsync
@RestController
@EnableTransactionManagement
@EnableJpaAuditing(auditorAwareRef = "auditorAware")
@MapperScan({"com.zq.logging.mapper"})
@SpringBootApplication(scanBasePackages = {"com.zq.admin", "com.zq.logging", "com.zq.common.config"})
public class AdminApplication {
public static void main(String[] args) {
SpringApplication.run(AdminApplication.class, args);
}
@Bean
public ServletWebServerFactory webServerFactory() {
TomcatServletWebServerFactory fa = new TomcatServletWebServerFactory();
fa.addConnectorCustomizers(connector -> connector.setProperty("relaxedQueryChars", "[]{}"));
return fa;
}
/**
* 访问首页提示
*
* @return /
*/
@AnonymousGetMapping("/")
public String index() {
return "Backend service started successfully";
}
}
/*
* Copyright 2019-2020 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.zq.admin.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* <p>
* 用于判断是否过滤数据权限
* 1、如果没有用到 @OneToOne 这种关联关系,只需要填写 fieldName [参考:DeptQueryCriteria.class]
* 2、如果用到了 @OneToOne ,fieldName 和 joinName 都需要填写,拿UserQueryCriteria.class举例:
* 应该是 @DataPermission(joinName = "dept", fieldName = "id")
* </p>
*
* @author Zheng Jie
* @website https://el-admin.vip
* @date 2020-05-07
**/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DataPermission {
/**
* Entity 中的字段名称
*/
String fieldName() default "";
/**
* Entity 中与部门关联的字段名称
*/
String joinName() default "";
}
/*
* Copyright 2019-2020 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.zq.admin.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author Zheng Jie
* @date 2019-6-4 13:52:30
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Query {
// Dong ZhaoYang 2017/8/7 基本对象的属性名
String propName() default "";
// Dong ZhaoYang 2017/8/7 查询方式
Type type() default Type.EQUAL;
/**
* 连接查询的属性名,如User类中的dept
*/
String joinName() default "";
/**
* 默认左连接
*/
Join join() default Join.LEFT;
/**
* 多字段模糊搜索,仅支持String类型字段,多个用逗号隔开, 如@Query(blurry = "email,username")
*/
String blurry() default "";
enum Type {
// jie 2019/6/4 相等
EQUAL
// Dong ZhaoYang 2017/8/7 大于等于
, GREATER_THAN
// Dong ZhaoYang 2017/8/7 小于等于
, LESS_THAN
// Dong ZhaoYang 2017/8/7 中模糊查询
, INNER_LIKE
// Dong ZhaoYang 2017/8/7 左模糊查询
, LEFT_LIKE
// Dong ZhaoYang 2017/8/7 右模糊查询
, RIGHT_LIKE
// Dong ZhaoYang 2017/8/7 小于
, LESS_THAN_NQ
// jie 2019/6/4 包含
, IN
// 不包含
, NOT_IN
// 不等于
, NOT_EQUAL
// between
, BETWEEN
// 不为空
, NOT_NULL
// 为空
, IS_NULL
}
/**
* @author Zheng Jie
* 适用于简单连接查询,复杂的请自定义该注解,或者使用sql查询
*/
enum Join {
/**
* jie 2019-6-4 13:18:30
*/
LEFT, RIGHT, INNER
}
}
package com.zq.admin.base;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.builder.ToStringBuilder;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.sql.Timestamp;
/**
* @author Zheng Jie
* @date 2019年10月24日20:48:53
*/
@Getter
@Setter
public class BaseDTO implements Serializable {
private String createBy;
private String updateBy;
private Timestamp createTime;
private Timestamp updateTime;
@Override
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this);
Field[] fields = this.getClass().getDeclaredFields();
try {
for (Field f : fields) {
f.setAccessible(true);
builder.append(f.getName(), f.get(this)).append("\n");
}
} catch (Exception e) {
builder.append("toString builder encounter an error");
}
return builder.toString();
}
}
/*
* Copyright 2019-2020 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.zq.admin.base;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.Column;
import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.sql.Timestamp;
/**
* 通用字段, is_del 根据需求自行添加
*
* @author Zheng Jie
* @Date 2019年10月24日20:46:32
*/
@Getter
@Setter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class BaseEntity implements Serializable {
@CreatedBy
@Column(name = "create_by", updatable = false)
@ApiModelProperty(value = "创建人", hidden = true)
private String createBy;
@LastModifiedBy
@Column(name = "update_by")
@ApiModelProperty(value = "更新人", hidden = true)
private String updateBy;
@CreationTimestamp
@Column(name = "create_time", updatable = false)
@ApiModelProperty(value = "创建时间", hidden = true)
private Timestamp createTime;
@UpdateTimestamp
@Column(name = "update_time")
@ApiModelProperty(value = "更新时间", hidden = true)
private Timestamp updateTime;
/* 分组校验 */
public @interface Create {
}
/* 分组校验 */
public @interface Update {
}
@Override
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this);
Field[] fields = this.getClass().getDeclaredFields();
try {
for (Field f : fields) {
f.setAccessible(true);
builder.append(f.getName(), f.get(this)).append("\n");
}
} catch (Exception e) {
builder.append("toString builder encounter an error");
}
return builder.toString();
}
}
/*
* Copyright 2019-2020 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.zq.admin.base;
import java.util.List;
/**
* @author Zheng Jie
* @date 2018-11-23
*/
public interface BaseMapper<D, E> {
/**
* DTO转Entity
*
* @param dto /
* @return /
*/
E toEntity(D dto);
/**
* Entity转DTO
*
* @param entity /
* @return /
*/
D toDto(E entity);
/**
* DTO集合转Entity集合
*
* @param dtoList /
* @return /
*/
List<E> toEntity(List<D> dtoList);
/**
* Entity集合转DTO集合
*
* @param entityList /
* @return /
*/
List<D> toDto(List<E> entityList);
}
/*
* Copyright 2019-2020 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.zq.admin.config;
import com.zq.admin.utils.SecurityUtils;
import org.springframework.data.domain.AuditorAware;
import org.springframework.stereotype.Component;
import java.util.Optional;
/**
* @author : Dong ZhaoYang
* @description : 设置审计
* @date : 2019/10/28
*/
@Component("auditorAware")
public class AuditorConfig implements AuditorAware<String> {
/**
* 返回操作员标志信息
*
* @return /
*/
@Override
public Optional<String> getCurrentAuditor() {
try {
// 这里应根据实际业务情况获取具体信息
return Optional.of(SecurityUtils.getCurrentUsername());
} catch (Exception ignored) {
}
// 用户定时任务,或者无Token调用的情况
return Optional.of("System");
}
}
/*
* 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.zq.admin.config;
import com.zq.admin.config.bean.LoginProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @apiNote 配置文件转换Pojo类的 统一配置 类
* @author: liaojinlong
* @date: 2020/6/10 19:04
*/
@Configuration
public class ConfigBeanConfiguration {
@Bean
@ConfigurationProperties(prefix = "login")
public LoginProperties loginProperties() {
return new LoginProperties();
}
}
/*
* Copyright 2019-2020 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.zq.admin.config;
import com.zq.admin.utils.SecurityUtils;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author Zheng Jie
*/
@Service(value = "el")
public class ElPermissionConfig {
public Boolean check(String... permissions) {
// 获取当前用户的所有权限
List<String> elPermissions = SecurityUtils.getCurrentUser().getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());
// 判断当前用户的所有权限是否包含接口上定义的权限
return elPermissions.contains("admin") || Arrays.stream(permissions).anyMatch(elPermissions::contains);
}
}
/*
* Copyright 2019-2020 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.zq.admin.config;
import com.zq.admin.constant.AdminConstant;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* @author Zheng Jie
*/
@Data
@Configuration
@ConfigurationProperties(prefix = "file")
public class FileProperties {
/**
* 文件大小限制
*/
private Long maxSize;
/**
* 头像大小限制
*/
private Long avatarMaxSize;
private ElPath mac;
private ElPath linux;
private ElPath windows;
public ElPath getPath() {
String os = System.getProperty("os.name");
if (os.toLowerCase().startsWith(AdminConstant.WIN)) {
return windows;
} else if (os.toLowerCase().startsWith(AdminConstant.MAC)) {
return mac;
}
return linux;
}
@Data
public static class ElPath {
private String path;
private String avatar;
}
}
/*
* Copyright 2019-2020 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.zq.admin.config;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* @author Zheng Jie
* @website https://el-admin.vip
* @description
* @date 2020-05-18
**/
@Data
@Component
public class RsaProperties {
public static String privateKey;
@Value("${rsa.private_key}")
public void setPrivateKey(String privateKey) {
RsaProperties.privateKey = privateKey;
}
}
\ No newline at end of file
/*
* Copyright 2019-2020 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.zq.admin.config;
import com.fasterxml.classmate.TypeResolver;
import com.google.common.base.Predicates;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.data.domain.Pageable;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.schema.AlternateTypeRule;
import springfox.documentation.schema.AlternateTypeRuleConvention;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
import java.util.List;
import static com.google.common.collect.Lists.newArrayList;
import static springfox.documentation.schema.AlternateTypeRules.newRule;
/**
* api页面 /doc.html
*
* @author Zheng Jie
* @date 2018-11-23
*/
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Value("${jwt.header}")
private String tokenHeader;
@Value("${swagger.enabled}")
private Boolean enabled;
@Bean
@SuppressWarnings("all")
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.enable(enabled)
.pathMapping("/")
.apiInfo(apiInfo())
.select()
.paths(Predicates.not(PathSelectors.regex("/error.*")))
.paths(PathSelectors.any())
.build()
//添加登陆认证
.securitySchemes(securitySchemes())
.securityContexts(securityContexts());
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.description("一个简单且易上手的 Spring boot 后台管理框架")
.title("EL-ADMIN 接口文档")
.version("2.6")
.build();
}
private List<SecurityScheme> securitySchemes() {
//设置请求头信息
List<SecurityScheme> securitySchemes = new ArrayList<>();
ApiKey apiKey = new ApiKey(tokenHeader, tokenHeader, "header");
securitySchemes.add(apiKey);
return securitySchemes;
}
private List<SecurityContext> securityContexts() {
//设置需要登录认证的路径
List<SecurityContext> securityContexts = new ArrayList<>();
// ^(?!auth).*$ 表示所有包含auth的接口不需要使用securitySchemes即不需要带token
// ^标识开始 ()里是一子表达式 ?!/auth表示匹配不是/auth的位置,匹配上则添加请求头,注意路径已/开头 .表示任意字符 *表示前面的字符匹配多次 $标识结束
securityContexts.add(getContextByPath());
return securityContexts;
}
private SecurityContext getContextByPath() {
return SecurityContext.builder()
.securityReferences(defaultAuth())
.forPaths(PathSelectors.regex("^(?!/auth).*$"))
.build();
}
private List<SecurityReference> defaultAuth() {
List<SecurityReference> securityReferences = new ArrayList<>();
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
authorizationScopes[0] = authorizationScope;
securityReferences.add(new SecurityReference(tokenHeader, authorizationScopes));
return securityReferences;
}
}
/**
* 将Pageable转换展示在swagger中
*/
@Configuration
class SwaggerDataConfig {
@Bean
public AlternateTypeRuleConvention pageableConvention(final TypeResolver resolver) {
return new AlternateTypeRuleConvention() {
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
@Override
public List<AlternateTypeRule> rules() {
return newArrayList(newRule(resolver.resolve(Pageable.class), resolver.resolve(Page.class)));
}
};
}
@ApiModel
@Data
private static class Page {
@ApiModelProperty("页码 (0..N)")
private Integer page;
@ApiModelProperty("每页显示的数目")
private Integer size;
@ApiModelProperty("以下列格式排序标准:property[,asc | desc]。 默认排序顺序为升序。 支持多种排序条件:如:id,asc")
private List<String> sort;
}
}
/*
* Copyright 2019-2020 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.zq.admin.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* @author ZhangHouYing
* @date 2019-08-24 15:44
*/
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
/*
* 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.zq.admin.config.bean;
import lombok.Data;
/**
* 登录验证码配置信息
*
* @author liaojinlong
* @date 2020/6/10 18:53
*/
@Data
public class LoginCode {
/**
* 验证码配置
*/
private LoginCodeEnum codeType;
/**
* 验证码有效期 分钟
*/
private Long expiration = 2L;
/**
* 验证码内容长度
*/
private int length = 2;
/**
* 验证码宽度
*/
private int width = 111;
/**
* 验证码高度
*/
private int height = 36;
/**
* 验证码字体
*/
private String fontName;
/**
* 字体大小
*/
private int fontSize = 25;
public LoginCodeEnum getCodeType() {
return codeType;
}
}
/*
* 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.zq.admin.config.bean;
/**
* 验证码配置枚举
*
* @author: liaojinlong
* @date: 2020/6/10 17:40
*/
public enum LoginCodeEnum {
/**
* 算数
*/
ARITHMETIC,
/**
* 中文
*/
CHINESE,
/**
* 中文闪图
*/
CHINESE_GIF,
/**
* 闪图
*/
GIF,
SPEC
}
/*
* 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.zq.admin.config.bean;
import com.wf.captcha.*;
import com.wf.captcha.base.Captcha;
import com.zq.admin.exception.BadConfigurationException;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import java.awt.*;
import java.util.Objects;
/**
* 配置文件读取
*
* @author liaojinlong
* @date loginCode.length0loginCode.length0/6/10 17:loginCode.length6
*/
@Data
public class LoginProperties {
/**
* 账号单用户 登录
*/
private boolean singleLogin = false;
private LoginCode loginCode;
public boolean isSingleLogin() {
return singleLogin;
}
/**
* 获取验证码生产类
*
* @return /
*/
public Captcha getCaptcha() {
if (Objects.isNull(loginCode)) {
loginCode = new LoginCode();
if (Objects.isNull(loginCode.getCodeType())) {
loginCode.setCodeType(LoginCodeEnum.ARITHMETIC);
}
}
return switchCaptcha(loginCode);
}
/**
* 依据配置信息生产验证码
*
* @param loginCode 验证码配置信息
* @return /
*/
private Captcha switchCaptcha(LoginCode loginCode) {
Captcha captcha;
synchronized (this) {
switch (loginCode.getCodeType()) {
case ARITHMETIC:
// 算术类型 https://gitee.com/whvse/EasyCaptcha
captcha = new FixedArithmeticCaptcha(loginCode.getWidth(), loginCode.getHeight());
// 几位数运算,默认是两位
captcha.setLen(loginCode.getLength());
break;
case CHINESE:
captcha = new ChineseCaptcha(loginCode.getWidth(), loginCode.getHeight());
captcha.setLen(loginCode.getLength());
break;
case CHINESE_GIF:
captcha = new ChineseGifCaptcha(loginCode.getWidth(), loginCode.getHeight());
captcha.setLen(loginCode.getLength());
break;
case GIF:
captcha = new GifCaptcha(loginCode.getWidth(), loginCode.getHeight());
captcha.setLen(loginCode.getLength());
break;
case SPEC:
captcha = new SpecCaptcha(loginCode.getWidth(), loginCode.getHeight());
captcha.setLen(loginCode.getLength());
break;
default:
throw new BadConfigurationException("验证码配置信息错误!正确配置查看 LoginCodeEnum ");
}
}
if (StringUtils.isNotBlank(loginCode.getFontName())) {
captcha.setFont(new Font(loginCode.getFontName(), Font.PLAIN, loginCode.getFontSize()));
}
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();
}
}
}
/*
* Copyright 2019-2020 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.zq.admin.config.security;
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.sendError(HttpServletResponse.SC_FORBIDDEN, accessDeniedException.getMessage());
}
}
/*
* Copyright 2019-2020 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.zq.admin.config.security;
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
*/
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException authException) throws IOException {
// 当用户尝试访问安全的REST资源而不提供任何凭据时,将调用此方法发送401 响应
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException == null ? "Unauthorized" : authException.getMessage());
}
}
/*
* Copyright 2019-2020 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.zq.admin.config.security;
import com.zq.admin.modules.security.service.OnlineUserService;
import com.zq.admin.modules.security.service.UserCacheManager;
import com.zq.common.annotation.AnonymousAccess;
import com.zq.common.config.security.SecurityProperties;
import com.zq.common.utils.RequestMethodEnum;
import lombok.RequiredArgsConstructor;
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.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
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.web.bind.annotation.RequestMethod;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import java.util.*;
/**
* @author Zheng Jie
*/
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
private final TokenProvider tokenProvider;
private final JwtAuthenticationEntryPoint authenticationErrorHandler;
private final JwtAccessDeniedHandler jwtAccessDeniedHandler;
private final ApplicationContext applicationContext;
private final SecurityProperties properties;
private final OnlineUserService onlineUserService;
private final UserCacheManager userCacheManager;
@Bean
GrantedAuthorityDefaults grantedAuthorityDefaults() {
// 去除 ROLE_ 前缀
return new GrantedAuthorityDefaults("");
}
@Bean
public PasswordEncoder passwordEncoder() {
// 密码加密方式
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
// 搜寻匿名标记 url: @AnonymousAccess
RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping) applicationContext.getBean("requestMappingHandlerMapping");
Map<RequestMappingInfo, HandlerMethod> handlerMethodMap = requestMappingHandlerMapping.getHandlerMethods();
// 获取匿名标记
Map<String, Set<String>> anonymousUrls = getAnonymousUrl(handlerMethodMap);
httpSecurity
// 禁用 CSRF
.csrf().disable()
// .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
// 授权异常
.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("/admin/swagger-ui.html").permitAll()
.antMatchers("/admin/swagger-resources/**").permitAll()
.antMatchers("/webjars/**").permitAll()
.antMatchers("/*/api-docs").permitAll()
// 文件
.antMatchers("/admin/avatar/**").permitAll()
.antMatchers("/admin/file/**").permitAll()
// 阿里巴巴 druid
.antMatchers("/admin/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());
}
private TokenConfigurer securityConfigurerAdapter() {
return new TokenConfigurer(tokenProvider, properties, onlineUserService, userCacheManager);
}
private Map<String, Set<String>> getAnonymousUrl(Map<RequestMappingInfo, HandlerMethod> handlerMethodMap) {
Map<String, Set<String>> anonymousUrls = new HashMap<>(8);
Set<String> get = new HashSet<>();
Set<String> post = new HashSet<>();
Set<String> put = new HashSet<>();
Set<String> patch = new HashSet<>();
Set<String> delete = new HashSet<>();
Set<String> all = new HashSet<>();
for (Map.Entry<RequestMappingInfo, HandlerMethod> infoEntry : handlerMethodMap.entrySet()) {
HandlerMethod handlerMethod = infoEntry.getValue();
AnonymousAccess anonymousAccess = handlerMethod.getMethodAnnotation(AnonymousAccess.class);
if (null != anonymousAccess) {
List<RequestMethod> requestMethods = new ArrayList<>(infoEntry.getKey().getMethodsCondition().getMethods());
RequestMethodEnum request = RequestMethodEnum.find(requestMethods.size() == 0 ? RequestMethodEnum.ALL.getType() : requestMethods.get(0).name());
switch (Objects.requireNonNull(request)) {
case GET:
get.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
break;
case POST:
post.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
break;
case PUT:
put.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
break;
case PATCH:
patch.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
break;
case DELETE:
delete.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
break;
default:
all.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
break;
}
}
}
anonymousUrls.put(RequestMethodEnum.GET.getType(), get);
anonymousUrls.put(RequestMethodEnum.POST.getType(), post);
anonymousUrls.put(RequestMethodEnum.PUT.getType(), put);
anonymousUrls.put(RequestMethodEnum.PATCH.getType(), patch);
anonymousUrls.put(RequestMethodEnum.DELETE.getType(), delete);
anonymousUrls.put(RequestMethodEnum.ALL.getType(), all);
return anonymousUrls;
}
}
/*
* Copyright 2019-2020 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.zq.admin.config.security;
import com.zq.admin.modules.security.service.OnlineUserService;
import com.zq.admin.modules.security.service.UserCacheManager;
import com.zq.common.config.security.SecurityProperties;
import lombok.RequiredArgsConstructor;
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;
private final UserCacheManager userCacheManager;
@Override
public void configure(HttpSecurity http) {
TokenFilter customFilter = new TokenFilter(tokenProvider, properties, onlineUserService, userCacheManager);
http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class);
}
}
/*
* Copyright 2019-2020 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.zq.admin.config.security;
import cn.hutool.core.util.StrUtil;
import com.zq.admin.modules.security.service.OnlineUserService;
import com.zq.admin.modules.security.service.UserCacheManager;
import com.zq.common.config.security.SecurityProperties;
import com.zq.common.context.ContextUtils;
import com.zq.common.vo.OnlineUserDto;
import io.jsonwebtoken.ExpiredJwtException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;
import java.util.Objects;
/**
* @author /
*/
public class TokenFilter extends GenericFilterBean {
private static final Logger log = LoggerFactory.getLogger(TokenFilter.class);
private final TokenProvider tokenProvider;
private final SecurityProperties properties;
private final OnlineUserService onlineUserService;
private final UserCacheManager userCacheManager;
/**
* @param tokenProvider Token
* @param properties JWT
* @param onlineUserService 用户在线
* @param userCacheManager 用户缓存工具
*/
public TokenFilter(TokenProvider tokenProvider, SecurityProperties properties, OnlineUserService onlineUserService, UserCacheManager userCacheManager) {
this.properties = properties;
this.onlineUserService = onlineUserService;
this.tokenProvider = tokenProvider;
this.userCacheManager = userCacheManager;
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
String token = tokenProvider.getToken(httpServletRequest);
// 对于 Token 为空的不需要去查 Redis
if (StrUtil.isNotBlank(token)) {
OnlineUserDto onlineUserDto = null;
boolean cleanUserCache = false;
try {
onlineUserDto = onlineUserService.getOne(properties.getOnlineKey() + token);
} catch (ExpiredJwtException e) {
log.error(e.getMessage());
cleanUserCache = true;
} finally {
if (cleanUserCache || Objects.isNull(onlineUserDto)) {
userCacheManager.cleanUserCache(String.valueOf(tokenProvider.getClaims(token).get(TokenProvider.AUTHORITIES_KEY)));
}
}
if (onlineUserDto != null && StringUtils.hasText(token)) {
Authentication authentication = tokenProvider.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
// Token 续期
tokenProvider.checkRenewal(token);
ContextUtils.setAdminContext(onlineUserDto);
}
}
filterChain.doFilter(servletRequest, servletResponse);
}
}
package com.zq.admin.config.security;/*
* Copyright 2019-2020 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.
*/
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.zq.common.config.redis.RedisUtils;
import com.zq.common.config.security.SecurityProperties;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
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.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import javax.xml.bind.DatatypeConverter;
import java.security.Key;
import java.util.ArrayList;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
* @author /
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class TokenProvider implements InitializingBean {
private final RedisUtils redisUtils;
private final SecurityProperties properties;
public static final String AUTHORITIES_KEY = "auth";
private static Key key;
private static SignatureAlgorithm signatureAlgorithm;
@Override
public void afterPropertiesSet() {
signatureAlgorithm = SignatureAlgorithm.HS512;
byte[] keyBytes = DatatypeConverter.parseBase64Binary(properties.getBase64Secret());
key = new SecretKeySpec(keyBytes, signatureAlgorithm.getJcaName());
}
public static String createToken(Authentication authentication) {
return Jwts.builder()
.claim(AUTHORITIES_KEY, authentication.getName())
.setSubject(authentication.getName())
.signWith(signatureAlgorithm, key)
// 加入ID确保生成的 Token 都不一致
.setId(IdUtil.simpleUUID())
.compact();
}
public Claims getClaims(String token) {
return Jwts.parser()
.setSigningKey(DatatypeConverter.parseBase64Binary(properties.getBase64Secret()))
.parseClaimsJws(token)
.getBody();
}
public Authentication getAuthentication(String token) {
Claims claims = getClaims(token);
User principal = new User(claims.getSubject(), "******", new ArrayList<>());
return new UsernamePasswordAuthenticationToken(principal, token, new ArrayList<>());
}
/**
* @param token 需要检查的token
*/
public void checkRenewal(String token) {
// 判断是否续期token,计算token的过期时间
long time = redisUtils.getExpire(properties.getOnlineKey() + token) * 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(properties.getOnlineKey() + token, renew, TimeUnit.MILLISECONDS);
}
}
public String getToken(HttpServletRequest request) {
String bearerToken = request.getHeader(properties.getHeader());
if (StringUtils.isBlank(bearerToken)) {
return null;
}
if (bearerToken.startsWith(properties.getTokenStartWith())) {
// 去掉令牌前缀
return bearerToken.replace(properties.getTokenStartWith(), "");
} else {
log.debug("非法Token:{}", bearerToken);
}
return null;
}
}
/*
* Copyright 2019-2020 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.zq.admin.constant;
/**
* 常用静态常量
*
* @author Zheng Jie
* @date 2018-12-26
*/
public class AdminConstant {
/**
* 用于IP定位转换
*/
public static final String REGION = "内网IP|内网IP";
/**
* win 系统
*/
public static final String WIN = "win";
/**
* mac 系统
*/
public static final String MAC = "mac";
/**
* 常用接口
*/
public static class Url {
// IP归属地查询
public static final String IP_URL = "http://whois.pconline.com.cn/ipJson.jsp?ip=%s&json=true";
}
}
/*
* Copyright 2019-2020 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.zq.admin.constant.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* <p>
* 验证码业务场景
* </p>
*
* @author Zheng Jie
* @date 2020-05-02
*/
@Getter
@AllArgsConstructor
public enum CodeBiEnum {
/* 旧邮箱修改邮箱 */
ONE(1, "旧邮箱修改邮箱"),
/* 通过邮箱修改密码 */
TWO(2, "通过邮箱修改密码");
private final Integer code;
private final String description;
public static CodeBiEnum find(Integer code) {
for (CodeBiEnum value : CodeBiEnum.values()) {
if (value.getCode().equals(code)) {
return value;
}
}
return null;
}
}
/*
* Copyright 2019-2020 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.zq.admin.constant.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* <p>
* 验证码业务场景对应的 Redis 中的 key
* </p>
*
* @author Zheng Jie
* @date 2020-05-02
*/
@Getter
@AllArgsConstructor
public enum CodeEnum {
/* 通过手机号码重置邮箱 */
PHONE_RESET_EMAIL_CODE("phone_reset_email_code_", "通过手机号码重置邮箱"),
/* 通过旧邮箱重置邮箱 */
EMAIL_RESET_EMAIL_CODE("email_reset_email_code_", "通过旧邮箱重置邮箱"),
/* 通过手机号码重置密码 */
PHONE_RESET_PWD_CODE("phone_reset_pwd_code_", "通过手机号码重置密码"),
/* 通过邮箱重置密码 */
EMAIL_RESET_PWD_CODE("email_reset_pwd_code_", "通过邮箱重置密码");
private final String key;
private final String description;
}
/*
* Copyright 2019-2020 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.zq.admin.constant.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* <p>
* 数据权限枚举
* </p>
*
* @author Zheng Jie
* @date 2020-05-07
*/
@Getter
@AllArgsConstructor
public enum DataScopeEnum {
/* 全部的数据权限 */
ALL("全部", "全部的数据权限"),
/* 自己部门的数据权限 */
THIS_LEVEL("本级", "自己部门的数据权限"),
/* 自定义的数据权限 */
CUSTOMIZE("自定义", "自定义的数据权限");
private final String value;
private final String description;
public static DataScopeEnum find(String val) {
for (DataScopeEnum dataScopeEnum : DataScopeEnum.values()) {
if (dataScopeEnum.getValue().equals(val)) {
return dataScopeEnum;
}
}
return null;
}
}
/*
* Copyright 2019-2020 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.zq.admin.constant.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @author Zheng Jie
* @website https://el-admin.vip
* @description
* @date 2020-06-10
**/
@Getter
@AllArgsConstructor
public enum RequestMethodEnum {
/**
* 搜寻 @AnonymousGetMapping
*/
GET("GET"),
/**
* 搜寻 @AnonymousPostMapping
*/
POST("POST"),
/**
* 搜寻 @AnonymousPutMapping
*/
PUT("PUT"),
/**
* 搜寻 @AnonymousPatchMapping
*/
PATCH("PATCH"),
/**
* 搜寻 @AnonymousDeleteMapping
*/
DELETE("DELETE"),
/**
* 否则就是所有 Request 接口都放行
*/
ALL("All");
/**
* Request 类型
*/
private final String type;
public static RequestMethodEnum find(String type) {
for (RequestMethodEnum value : RequestMethodEnum.values()) {
if (value.getType().equals(type)) {
return value;
}
}
return ALL;
}
}
/*
* 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.zq.admin.exception;
/**
* 统一关于错误配置信息 异常
*
* @author: liaojinlong
* @date: 2020/6/10 18:06
*/
public class BadConfigurationException extends RuntimeException {
/**
* Constructs a new runtime exception with {@code null} as its
* detail message. The cause is not initialized, and may subsequently be
* initialized by a call to {@link #initCause}.
*/
public BadConfigurationException() {
super();
}
/**
* Constructs a new runtime exception with the specified detail message.
* The cause is not initialized, and may subsequently be initialized by a
* call to {@link #initCause}.
*
* @param message the detail message. The detail message is saved for
* later retrieval by the {@link #getMessage()} method.
*/
public BadConfigurationException(String message) {
super(message);
}
/**
* Constructs a new runtime exception with the specified detail message and
* cause. <p>Note that the detail message associated with
* {@code cause} is <i>not</i> automatically incorporated in
* this runtime exception's detail message.
*
* @param message the detail message (which is saved for later retrieval
* by the {@link #getMessage()} method).
* @param cause the cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A {@code null} value is
* permitted, and indicates that the cause is nonexistent or
* unknown.)
* @since 1.4
*/
public BadConfigurationException(String message, Throwable cause) {
super(message, cause);
}
/**
* Constructs a new runtime exception with the specified cause and a
* detail message of {@code (cause==null ? null : cause.toString())}
* (which typically contains the class and detail message of
* {@code cause}). This constructor is useful for runtime exceptions
* that are little more than wrappers for other throwables.
*
* @param cause the cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A {@code null} value is
* permitted, and indicates that the cause is nonexistent or
* unknown.)
* @since 1.4
*/
public BadConfigurationException(Throwable cause) {
super(cause);
}
/**
* Constructs a new runtime exception with the specified detail
* message, cause, suppression enabled or disabled, and writable
* stack trace enabled or disabled.
*
* @param message the detail message.
* @param cause the cause. (A {@code null} value is permitted,
* and indicates that the cause is nonexistent or unknown.)
* @param enableSuppression whether or not suppression is enabled
* or disabled
* @param writableStackTrace whether or not the stack trace should
* be writable
* @since 1.7
*/
protected BadConfigurationException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
/*
* Copyright 2019-2020 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.zq.admin.exception;
import lombok.Getter;
import org.springframework.http.HttpStatus;
import static org.springframework.http.HttpStatus.BAD_REQUEST;
/**
* @author Zheng Jie
* @date 2018-11-23
* 统一异常处理
*/
@Getter
public class BadRequestException extends RuntimeException {
private Integer status = BAD_REQUEST.value();
public BadRequestException(String msg) {
super(msg);
}
public BadRequestException(HttpStatus status, String msg) {
super(msg);
this.status = status.value();
}
}
/*
* Copyright 2019-2020 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.zq.admin.exception;
import org.springframework.util.StringUtils;
/**
* @author Zheng Jie
* @date 2018-11-23
*/
public class EntityExistException extends RuntimeException {
public EntityExistException(Class clazz, String field, String val) {
super(EntityExistException.generateMessage(clazz.getSimpleName(), field, val));
}
private static String generateMessage(String entity, String field, String val) {
return StringUtils.capitalize(entity)
+ " with " + field + " " + val + " existed";
}
}
\ No newline at end of file
/*
* Copyright 2019-2020 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.zq.admin.exception;
import org.springframework.util.StringUtils;
/**
* @author Zheng Jie
* @date 2018-11-23
*/
public class EntityNotFoundException extends RuntimeException {
public EntityNotFoundException(Class clazz, String field, String val) {
super(EntityNotFoundException.generateMessage(clazz.getSimpleName(), field, val));
}
private static String generateMessage(String entity, String field, String val) {
return StringUtils.capitalize(entity)
+ " with " + field + " " + val + " does not exist";
}
}
\ No newline at end of file
/*
* Copyright 2019-2020 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.zq.admin.exception.handler;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.time.LocalDateTime;
/**
* @author Zheng Jie
* @date 2018-11-23
*/
@Data
class ApiError {
private Integer status = 400;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime timestamp;
private String message;
private ApiError() {
timestamp = LocalDateTime.now();
}
public static ApiError error(String message) {
ApiError apiError = new ApiError();
apiError.setMessage(message);
return apiError;
}
public static ApiError error(Integer status, String message) {
ApiError apiError = new ApiError();
apiError.setStatus(status);
apiError.setMessage(message);
return apiError;
}
}
/*
* Copyright 2019-2020 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.zq.admin.exception.handler;
import com.zq.admin.exception.BadRequestException;
import com.zq.admin.exception.EntityExistException;
import com.zq.admin.exception.EntityNotFoundException;
import com.zq.common.utils.ThrowableUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.Objects;
import static org.springframework.http.HttpStatus.NOT_FOUND;
/**
* @author Zheng Jie
* @date 2018-11-23
*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 处理所有不可知的异常
*/
@ExceptionHandler(Throwable.class)
public ResponseEntity<ApiError> handleException(Throwable e) {
// 打印堆栈信息
log.error(ThrowableUtil.getStackTrace(e));
return buildResponseEntity(ApiError.error(e.getMessage()));
}
/**
* BadCredentialsException
*/
@ExceptionHandler(BadCredentialsException.class)
public ResponseEntity<ApiError> badCredentialsException(BadCredentialsException e) {
// 打印堆栈信息
String message = "坏的凭证".equals(e.getMessage()) ? "用户名或密码不正确" : e.getMessage();
log.error(message);
return buildResponseEntity(ApiError.error(message));
}
/**
* 处理自定义异常
*/
@ExceptionHandler(value = BadRequestException.class)
public ResponseEntity<ApiError> badRequestException(BadRequestException e) {
// 打印堆栈信息
log.error(ThrowableUtil.getStackTrace(e));
return buildResponseEntity(ApiError.error(e.getStatus(), e.getMessage()));
}
/**
* 处理 EntityExist
*/
@ExceptionHandler(value = EntityExistException.class)
public ResponseEntity<ApiError> entityExistException(EntityExistException e) {
// 打印堆栈信息
log.error(ThrowableUtil.getStackTrace(e));
return buildResponseEntity(ApiError.error(e.getMessage()));
}
/**
* 处理 EntityNotFound
*/
@ExceptionHandler(value = EntityNotFoundException.class)
public ResponseEntity<ApiError> entityNotFoundException(EntityNotFoundException e) {
// 打印堆栈信息
log.error(ThrowableUtil.getStackTrace(e));
return buildResponseEntity(ApiError.error(NOT_FOUND.value(), e.getMessage()));
}
/**
* 处理所有接口数据验证异常
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ApiError> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
// 打印堆栈信息
log.error(ThrowableUtil.getStackTrace(e));
String[] str = Objects.requireNonNull(e.getBindingResult().getAllErrors().get(0).getCodes())[1].split("\\.");
String message = e.getBindingResult().getAllErrors().get(0).getDefaultMessage();
String msg = "不能为空";
if (msg.equals(message)) {
message = str[1] + ":" + message;
}
return buildResponseEntity(ApiError.error(message));
}
/**
* 统一返回
*/
private ResponseEntity<ApiError> buildResponseEntity(ApiError apiError) {
return new ResponseEntity<>(apiError, HttpStatus.valueOf(apiError.getStatus()));
}
}
/*
* Copyright 2019-2020 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.zq.admin.modules.generator.domain;
import com.zq.admin.modules.generator.utils.GenUtil;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.persistence.*;
import java.io.Serializable;
/**
* 列的数据信息
*
* @author Zheng Jie
* @date 2019-01-02
*/
@Getter
@Setter
@Entity
@NoArgsConstructor
@Table(name = "code_column_config")
public class ColumnInfo implements Serializable {
@Id
@Column(name = "column_id")
@ApiModelProperty(value = "ID", hidden = true)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ApiModelProperty(value = "表名")
private String tableName;
@ApiModelProperty(value = "数据库字段名称")
private String columnName;
@ApiModelProperty(value = "数据库字段类型")
private String columnType;
@ApiModelProperty(value = "数据库字段键类型")
private String keyType;
@ApiModelProperty(value = "字段额外的参数")
private String extra;
@ApiModelProperty(value = "数据库字段描述")
private String remark;
@ApiModelProperty(value = "是否必填")
private Boolean notNull;
@ApiModelProperty(value = "是否在列表显示")
private Boolean listShow;
@ApiModelProperty(value = "是否表单显示")
private Boolean formShow;
@ApiModelProperty(value = "表单类型")
private String formType;
@ApiModelProperty(value = "查询 1:模糊 2:精确")
private String queryType;
@ApiModelProperty(value = "字典名称")
private String dictName;
@ApiModelProperty(value = "日期注解")
private String dateAnnotation;
public ColumnInfo(String tableName, String columnName, Boolean notNull, String columnType, String remark, String keyType, String extra) {
this.tableName = tableName;
this.columnName = columnName;
this.columnType = columnType;
this.keyType = keyType;
this.extra = extra;
this.notNull = notNull;
if (GenUtil.PK.equalsIgnoreCase(keyType) && GenUtil.EXTRA.equalsIgnoreCase(extra)) {
this.notNull = false;
}
this.remark = remark;
this.listShow = true;
this.formShow = true;
}
}
/*
* Copyright 2019-2020 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.zq.admin.modules.generator.domain;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
/**
* 代码生成配置
*
* @author Zheng Jie
* @date 2019-01-03
*/
@Getter
@Setter
@Entity
@NoArgsConstructor
@Table(name = "code_gen_config")
public class GenConfig implements Serializable {
public GenConfig(String tableName) {
this.tableName = tableName;
}
@Id
@Column(name = "config_id")
@ApiModelProperty(value = "ID", hidden = true)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotBlank
@ApiModelProperty(value = "表名")
private String tableName;
@ApiModelProperty(value = "接口名称")
private String apiAlias;
@NotBlank
@ApiModelProperty(value = "包路径")
private String pack;
@NotBlank
@ApiModelProperty(value = "模块名")
private String moduleName;
@NotBlank
@ApiModelProperty(value = "前端文件路径")
private String path;
@ApiModelProperty(value = "前端文件路径")
private String apiPath;
@ApiModelProperty(value = "作者")
private String author;
@ApiModelProperty(value = "表前缀")
private String prefix;
@ApiModelProperty(value = "是否覆盖")
private Boolean cover = false;
}
/*
* Copyright 2019-2020 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.zq.admin.modules.generator.domain.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 表的数据信息
*
* @author Zheng Jie
* @date 2019-01-02
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class TableInfo {
/**
* 表名称
*/
private Object tableName;
/**
* 创建日期
*/
private Object createTime;
/**
* 数据库引擎
*/
private Object engine;
/**
* 编码集
*/
private Object coding;
/**
* 备注
*/
private Object remark;
}
/*
* Copyright 2019-2020 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.zq.admin.modules.generator.repository;
import com.zq.admin.modules.generator.domain.ColumnInfo;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
/**
* @author Zheng Jie
* @date 2019-01-14
*/
public interface ColumnInfoRepository extends JpaRepository<ColumnInfo, Long> {
/**
* 查询表信息
*
* @param tableName 表格名
* @return 表信息
*/
List<ColumnInfo> findByTableNameOrderByIdAsc(String tableName);
}
/*
* Copyright 2019-2020 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.zq.admin.modules.generator.repository;
import com.zq.admin.modules.generator.domain.GenConfig;
import org.springframework.data.jpa.repository.JpaRepository;
/**
* @author Zheng Jie
* @date 2019-01-14
*/
public interface GenConfigRepository extends JpaRepository<GenConfig, Long> {
/**
* 查询表配置
*
* @param tableName 表名
* @return /
*/
GenConfig findByTableName(String tableName);
}
/*
* Copyright 2019-2020 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.zq.admin.modules.generator.rest;
import com.zq.admin.modules.generator.domain.GenConfig;
import com.zq.admin.modules.generator.service.GenConfigService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
/**
* @author Zheng Jie
* @date 2019-01-14
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/admin/genConfig")
@Api(tags = "系统:代码生成器配置管理")
public class GenConfigController {
private final GenConfigService genConfigService;
@ApiOperation("查询")
@GetMapping(value = "/{tableName}")
public ResponseEntity<Object> queryGenConfig(@PathVariable String tableName) {
return new ResponseEntity<>(genConfigService.find(tableName), HttpStatus.OK);
}
@PutMapping
@ApiOperation("修改")
public ResponseEntity<Object> updateGenConfig(@Validated @RequestBody GenConfig genConfig) {
return new ResponseEntity<>(genConfigService.update(genConfig.getTableName(), genConfig), HttpStatus.OK);
}
}
/*
* Copyright 2019-2020 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.zq.admin.modules.generator.rest;
import com.zq.admin.exception.BadRequestException;
import com.zq.admin.modules.generator.domain.ColumnInfo;
import com.zq.admin.modules.generator.service.GenConfigService;
import com.zq.admin.modules.generator.service.GeneratorService;
import com.zq.admin.utils.PageUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* @author Zheng Jie
* @date 2019-01-02
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/admin/generator")
@Api(tags = "系统:代码生成管理")
public class GeneratorController {
private final GeneratorService generatorService;
private final GenConfigService genConfigService;
@Value("${generator.enabled}")
private Boolean generatorEnabled;
@ApiOperation("查询数据库数据")
@GetMapping(value = "/tables/all")
public ResponseEntity<Object> queryAllTables() {
return new ResponseEntity<>(generatorService.getTables(), HttpStatus.OK);
}
@ApiOperation("查询数据库数据")
@GetMapping(value = "/tables")
public ResponseEntity<Object> queryTables(@RequestParam(defaultValue = "") String name,
@RequestParam(defaultValue = "0") Integer page,
@RequestParam(defaultValue = "10") Integer size) {
int[] startEnd = PageUtil.transToStartEnd(page, size);
return new ResponseEntity<>(generatorService.getTables(name, startEnd), HttpStatus.OK);
}
@ApiOperation("查询字段数据")
@GetMapping(value = "/columns")
public ResponseEntity<Object> queryColumns(@RequestParam String tableName) {
List<ColumnInfo> columnInfos = generatorService.getColumns(tableName);
return new ResponseEntity<>(PageUtil.toPage(columnInfos, columnInfos.size()), HttpStatus.OK);
}
@ApiOperation("保存字段数据")
@PutMapping
public ResponseEntity<HttpStatus> saveColumn(@RequestBody List<ColumnInfo> columnInfos) {
generatorService.save(columnInfos);
return new ResponseEntity<>(HttpStatus.OK);
}
@ApiOperation("同步字段数据")
@PostMapping(value = "sync")
public ResponseEntity<HttpStatus> syncColumn(@RequestBody List<String> tables) {
for (String table : tables) {
generatorService.sync(generatorService.getColumns(table), generatorService.query(table));
}
return new ResponseEntity<>(HttpStatus.OK);
}
@ApiOperation("生成代码")
@PostMapping(value = "/{tableName}/{type}")
public ResponseEntity<Object> generatorCode(@PathVariable String tableName, @PathVariable Integer type, HttpServletRequest request, HttpServletResponse response) {
if (!generatorEnabled && type == 0) {
throw new BadRequestException("此环境不允许生成代码,请选择预览或者下载查看!");
}
switch (type) {
// 生成代码
case 0:
generatorService.generator(genConfigService.find(tableName), generatorService.getColumns(tableName));
break;
// 预览
case 1:
return generatorService.preview(genConfigService.find(tableName), generatorService.getColumns(tableName));
// 打包
case 2:
generatorService.download(genConfigService.find(tableName), generatorService.getColumns(tableName), request, response);
break;
default:
throw new BadRequestException("没有这个选项");
}
return new ResponseEntity<>(HttpStatus.OK);
}
}
/*
* Copyright 2019-2020 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.zq.admin.modules.generator.service;
import com.zq.admin.modules.generator.domain.GenConfig;
/**
* @author Zheng Jie
* @date 2019-01-14
*/
public interface GenConfigService {
/**
* 查询表配置
*
* @param tableName 表名
* @return 表配置
*/
GenConfig find(String tableName);
/**
* 更新表配置
*
* @param tableName 表名
* @param genConfig 表配置
* @return 表配置
*/
GenConfig update(String tableName, GenConfig genConfig);
}
/*
* Copyright 2019-2020 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.zq.admin.modules.generator.service;
import com.zq.admin.modules.generator.domain.ColumnInfo;
import com.zq.admin.modules.generator.domain.GenConfig;
import org.springframework.http.ResponseEntity;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* @author Zheng Jie
* @date 2019-01-02
*/
public interface GeneratorService {
/**
* 查询数据库元数据
*
* @param name 表名
* @param startEnd 分页参数
* @return /
*/
Object getTables(String name, int[] startEnd);
/**
* 得到数据表的元数据
*
* @param name 表名
* @return /
*/
List<ColumnInfo> getColumns(String name);
/**
* 同步表数据
*
* @param columnInfos /
* @param columnInfoList /
*/
void sync(List<ColumnInfo> columnInfos, List<ColumnInfo> columnInfoList);
/**
* 保持数据
*
* @param columnInfos /
*/
void save(List<ColumnInfo> columnInfos);
/**
* 获取所有table
*
* @return /
*/
Object getTables();
/**
* 代码生成
*
* @param genConfig 配置信息
* @param columns 字段信息
*/
void generator(GenConfig genConfig, List<ColumnInfo> columns);
/**
* 预览
*
* @param genConfig 配置信息
* @param columns 字段信息
* @return /
*/
ResponseEntity<Object> preview(GenConfig genConfig, List<ColumnInfo> columns);
/**
* 打包下载
*
* @param genConfig 配置信息
* @param columns 字段信息
* @param request /
* @param response /
*/
void download(GenConfig genConfig, List<ColumnInfo> columns, HttpServletRequest request, HttpServletResponse response);
/**
* 查询数据库的表字段数据数据
*
* @param table /
* @return /
*/
List<ColumnInfo> query(String table);
}
/*
* Copyright 2019-2020 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.zq.admin.modules.generator.service.impl;
import com.zq.admin.modules.generator.domain.GenConfig;
import com.zq.admin.modules.generator.repository.GenConfigRepository;
import com.zq.admin.modules.generator.service.GenConfigService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.io.File;
/**
* @author Zheng Jie
* @date 2019-01-14
*/
@Service
@RequiredArgsConstructor
public class GenConfigServiceImpl implements GenConfigService {
private final GenConfigRepository genConfigRepository;
@Override
public GenConfig find(String tableName) {
GenConfig genConfig = genConfigRepository.findByTableName(tableName);
if (genConfig == null) {
return new GenConfig(tableName);
}
return genConfig;
}
@Override
public GenConfig update(String tableName, GenConfig genConfig) {
String separator = File.separator;
String[] paths;
String symbol = "\\";
if (symbol.equals(separator)) {
paths = genConfig.getPath().split("\\\\");
} else {
paths = genConfig.getPath().split(File.separator);
}
StringBuilder api = new StringBuilder();
for (String path : paths) {
api.append(path);
api.append(separator);
if ("src".equals(path)) {
api.append("api");
break;
}
}
genConfig.setApiPath(api.toString());
return genConfigRepository.save(genConfig);
}
}
/*
* Copyright 2019-2020 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.zq.admin.modules.generator.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ZipUtil;
import com.zq.admin.exception.BadRequestException;
import com.zq.admin.modules.generator.domain.ColumnInfo;
import com.zq.admin.modules.generator.domain.GenConfig;
import com.zq.admin.modules.generator.domain.vo.TableInfo;
import com.zq.admin.modules.generator.repository.ColumnInfoRepository;
import com.zq.admin.modules.generator.service.GeneratorService;
import com.zq.admin.modules.generator.utils.GenUtil;
import com.zq.admin.utils.FileUtil;
import com.zq.admin.utils.PageUtil;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author Zheng Jie
* @date 2019-01-02
*/
@Service
@RequiredArgsConstructor
public class GeneratorServiceImpl implements GeneratorService {
private static final Logger log = LoggerFactory.getLogger(GeneratorServiceImpl.class);
@PersistenceContext
private EntityManager em;
private final ColumnInfoRepository columnInfoRepository;
@Override
public Object getTables() {
// 使用预编译防止sql注入
String sql = "select table_name ,create_time , engine, table_collation, table_comment from information_schema.tables " +
"where table_schema = (select database()) " +
"order by create_time desc";
Query query = em.createNativeQuery(sql);
return query.getResultList();
}
@Override
public Object getTables(String name, int[] startEnd) {
// 使用预编译防止sql注入
String sql = "select table_name ,create_time , engine, table_collation, table_comment from information_schema.tables " +
"where table_schema = (select database()) " +
"and table_name like :table order by create_time desc";
Query query = em.createNativeQuery(sql);
query.setFirstResult(startEnd[0]);
query.setMaxResults(startEnd[1] - startEnd[0]);
query.setParameter("table", StringUtils.isNotBlank(name) ? ("%" + name + "%") : "%%");
List result = query.getResultList();
List<TableInfo> tableInfos = new ArrayList<>();
for (Object obj : result) {
Object[] arr = (Object[]) obj;
tableInfos.add(new TableInfo(arr[0], arr[1], arr[2], arr[3], ObjectUtil.isNotEmpty(arr[4]) ? arr[4] : "-"));
}
String countSql = "select count(1) from information_schema.tables " +
"where table_schema = (select database()) and table_name like :table";
Query queryCount = em.createNativeQuery(countSql);
queryCount.setParameter("table", StringUtils.isNotBlank(name) ? ("%" + name + "%") : "%%");
Object totalElements = queryCount.getSingleResult();
return PageUtil.toPage(tableInfos, totalElements);
}
@Override
public List<ColumnInfo> getColumns(String tableName) {
List<ColumnInfo> columnInfos = columnInfoRepository.findByTableNameOrderByIdAsc(tableName);
if (CollectionUtil.isNotEmpty(columnInfos)) {
return columnInfos;
} else {
columnInfos = query(tableName);
return columnInfoRepository.saveAll(columnInfos);
}
}
@Override
public List<ColumnInfo> query(String tableName) {
// 使用预编译防止sql注入
String sql = "select column_name, is_nullable, data_type, column_comment, column_key, extra from information_schema.columns " +
"where table_name = ? and table_schema = (select database()) order by ordinal_position";
Query query = em.createNativeQuery(sql);
query.setParameter(1, tableName);
List result = query.getResultList();
List<ColumnInfo> columnInfos = new ArrayList<>();
for (Object obj : result) {
Object[] arr = (Object[]) obj;
columnInfos.add(
new ColumnInfo(
tableName,
arr[0].toString(),
"NO".equals(arr[1]),
arr[2].toString(),
ObjectUtil.isNotNull(arr[3]) ? arr[3].toString() : null,
ObjectUtil.isNotNull(arr[4]) ? arr[4].toString() : null,
ObjectUtil.isNotNull(arr[5]) ? arr[5].toString() : null)
);
}
return columnInfos;
}
@Override
public void sync(List<ColumnInfo> columnInfos, List<ColumnInfo> columnInfoList) {
// 第一种情况,数据库类字段改变或者新增字段
for (ColumnInfo columnInfo : columnInfoList) {
// 根据字段名称查找
List<ColumnInfo> columns = columnInfos.stream().filter(c -> c.getColumnName().equals(columnInfo.getColumnName())).collect(Collectors.toList());
// 如果能找到,就修改部分可能被字段
if (CollectionUtil.isNotEmpty(columns)) {
ColumnInfo column = columns.get(0);
column.setColumnType(columnInfo.getColumnType());
column.setExtra(columnInfo.getExtra());
column.setKeyType(columnInfo.getKeyType());
if (StringUtils.isBlank(column.getRemark())) {
column.setRemark(columnInfo.getRemark());
}
columnInfoRepository.save(column);
} else {
// 如果找不到,则保存新字段信息
columnInfoRepository.save(columnInfo);
}
}
// 第二种情况,数据库字段删除了
for (ColumnInfo columnInfo : columnInfos) {
// 根据字段名称查找
List<ColumnInfo> columns = columnInfoList.stream().filter(c -> c.getColumnName().equals(columnInfo.getColumnName())).collect(Collectors.toList());
// 如果找不到,就代表字段被删除了,则需要删除该字段
if (CollectionUtil.isEmpty(columns)) {
columnInfoRepository.delete(columnInfo);
}
}
}
@Override
public void save(List<ColumnInfo> columnInfos) {
columnInfoRepository.saveAll(columnInfos);
}
@Override
public void generator(GenConfig genConfig, List<ColumnInfo> columns) {
if (genConfig.getId() == null) {
throw new BadRequestException("请先配置生成器");
}
try {
GenUtil.generatorCode(columns, genConfig);
} catch (IOException e) {
log.error(e.getMessage(), e);
throw new BadRequestException("生成失败,请手动处理已生成的文件");
}
}
@Override
public ResponseEntity<Object> preview(GenConfig genConfig, List<ColumnInfo> columns) {
if (genConfig.getId() == null) {
throw new BadRequestException("请先配置生成器");
}
List<Map<String, Object>> genList = GenUtil.preview(columns, genConfig);
return new ResponseEntity<>(genList, HttpStatus.OK);
}
@Override
public void download(GenConfig genConfig, List<ColumnInfo> columns, HttpServletRequest request, HttpServletResponse response) {
if (genConfig.getId() == null) {
throw new BadRequestException("请先配置生成器");
}
try {
File file = new File(GenUtil.download(columns, genConfig));
String zipPath = file.getPath() + ".zip";
ZipUtil.zip(file.getPath(), zipPath);
FileUtil.downloadFile(request, response, new File(zipPath), true);
} catch (IOException e) {
throw new BadRequestException("打包失败");
}
}
}
/*
* Copyright 2019-2020 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.zq.admin.modules.generator.utils;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* sql字段转java
*
* @author Zheng Jie
* @date 2019-01-03
*/
public class ColUtil {
private static final Logger log = LoggerFactory.getLogger(ColUtil.class);
/**
* 转换mysql数据类型为java数据类型
*
* @param type 数据库字段类型
* @return String
*/
static String cloToJava(String type) {
Configuration config = getConfig();
assert config != null;
return config.getString(type, "unknowType");
}
/**
* 获取配置信息
*/
public static PropertiesConfiguration getConfig() {
try {
return new PropertiesConfiguration("generator.properties");
} catch (ConfigurationException e) {
log.error(e.getMessage(), e);
}
return null;
}
}
/*
* Copyright 2019-2020 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.zq.admin.modules.mnt.domain;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.zq.admin.base.BaseEntity;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import java.io.Serializable;
/**
* @author zhanghouying
* @date 2019-08-24
*/
@Entity
@Getter
@Setter
@Table(name = "mnt_app")
public class App extends BaseEntity implements Serializable {
@Id
@Column(name = "app_id")
@ApiModelProperty(value = "ID", hidden = true)
@GeneratedValue(strategy = GenerationType.IDENTITY)
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));
}
}
/*
* Copyright 2019-2020 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.zq.admin.modules.mnt.domain;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.zq.admin.base.BaseEntity;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;
/**
* @author zhanghouying
* @date 2019-08-24
*/
@Entity
@Getter
@Setter
@Table(name = "mnt_database")
public class Database extends BaseEntity implements Serializable {
@Id
@Column(name = "db_id")
@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));
}
}
/*
* Copyright 2019-2020 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.zq.admin.modules.mnt.domain;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.zq.admin.base.BaseEntity;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Set;
/**
* @author zhanghouying
* @date 2019-08-24
*/
@Entity
@Getter
@Setter
@Table(name = "mnt_deploy")
public class Deploy extends BaseEntity implements Serializable {
@Id
@Column(name = "deploy_id")
@ApiModelProperty(value = "ID", hidden = true)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToMany
@ApiModelProperty(name = "服务器", hidden = true)
@JoinTable(name = "mnt_deploy_server",
joinColumns = {@JoinColumn(name = "deploy_id", referencedColumnName = "deploy_id")},
inverseJoinColumns = {@JoinColumn(name = "server_id", referencedColumnName = "server_id")})
private Set<ServerDeploy> deploys;
@ManyToOne
@JoinColumn(name = "app_id")
@ApiModelProperty(value = "应用编号")
private App app;
public void copy(Deploy source) {
BeanUtil.copyProperties(source, this, CopyOptions.create().setIgnoreNullValue(true));
}
}
/*
* Copyright 2019-2020 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.zq.admin.modules.mnt.domain;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.CreationTimestamp;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;
import java.sql.Timestamp;
/**
* @author zhanghouying
* @date 2019-08-24
*/
@Entity
@Getter
@Setter
@Table(name = "mnt_deploy_history")
public class DeployHistory implements Serializable {
@Id
@Column(name = "history_id")
@ApiModelProperty(value = "ID", hidden = true)
private String id;
@ApiModelProperty(value = "应用名称")
private String appName;
@ApiModelProperty(value = "IP")
private String ip;
@CreationTimestamp
@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));
}
}
/*
* Copyright 2019-2020 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.zq.admin.modules.mnt.domain;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.zq.admin.base.BaseEntity;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Objects;
/**
* @author zhanghouying
* @date 2019-08-24
*/
@Entity
@Getter
@Setter
@Table(name = "mnt_server")
public class ServerDeploy extends BaseEntity implements Serializable {
@Id
@Column(name = "server_id")
@ApiModelProperty(value = "ID", hidden = true)
@GeneratedValue(strategy = GenerationType.IDENTITY)
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(ServerDeploy 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;
}
ServerDeploy that = (ServerDeploy) o;
return Objects.equals(id, that.id) &&
Objects.equals(name, that.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name);
}
}
/*
* Copyright 2019-2020 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.zq.admin.modules.mnt.repository;
import com.zq.admin.modules.mnt.domain.App;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
/**
* @author zhanghouying
* @date 2019-08-24
*/
public interface AppRepository extends JpaRepository<App, Long>, JpaSpecificationExecutor<App> {
}
/*
* Copyright 2019-2020 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.zq.admin.modules.mnt.repository;
import com.zq.admin.modules.mnt.domain.Database;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
/**
* @author zhanghouying
* @date 2019-08-24
*/
public interface DatabaseRepository extends JpaRepository<Database, String>, JpaSpecificationExecutor<Database> {
}
/*
* Copyright 2019-2020 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.zq.admin.modules.mnt.repository;
import com.zq.admin.modules.mnt.domain.DeployHistory;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
/**
* @author zhanghouying
* @date 2019-08-24
*/
public interface DeployHistoryRepository extends JpaRepository<DeployHistory, String>, JpaSpecificationExecutor<DeployHistory> {
}
/*
* Copyright 2019-2020 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.zq.admin.modules.mnt.repository;
import com.zq.admin.modules.mnt.domain.Deploy;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
/**
* @author zhanghouying
* @date 2019-08-24
*/
public interface DeployRepository extends JpaRepository<Deploy, Long>, JpaSpecificationExecutor<Deploy> {
}
/*
* Copyright 2019-2020 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.zq.admin.modules.mnt.repository;
import com.zq.admin.modules.mnt.domain.ServerDeploy;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
/**
* @author zhanghouying
* @date 2019-08-24
*/
public interface ServerDeployRepository extends JpaRepository<ServerDeploy, Long>, JpaSpecificationExecutor<ServerDeploy> {
/**
* 根据IP查询
*
* @param ip /
* @return /
*/
ServerDeploy findByIp(String ip);
}
/*
* Copyright 2019-2020 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.zq.admin.modules.mnt.rest;
import com.zq.admin.modules.mnt.domain.App;
import com.zq.admin.modules.mnt.service.AppService;
import com.zq.admin.modules.mnt.service.dto.AppQueryCriteria;
import com.zq.logging.annotation.Log;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
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.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("/admin/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<Object> queryApp(AppQueryCriteria criteria, Pageable pageable) {
return new ResponseEntity<>(appService.queryAll(criteria, pageable), 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);
}
}
/*
* Copyright 2019-2020 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.zq.admin.modules.mnt.rest;
import com.zq.admin.exception.BadRequestException;
import com.zq.admin.modules.mnt.domain.Database;
import com.zq.admin.modules.mnt.service.DatabaseService;
import com.zq.admin.modules.mnt.service.dto.DatabaseDto;
import com.zq.admin.modules.mnt.service.dto.DatabaseQueryCriteria;
import com.zq.admin.modules.mnt.util.SqlUtils;
import com.zq.admin.utils.FileUtil;
import com.zq.logging.annotation.Log;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
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.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("/admin/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<Object> queryDatabase(DatabaseQueryCriteria criteria, Pageable pageable) {
return new ResponseEntity<>(databaseService.queryAll(criteria, pageable), 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");
DatabaseDto database = databaseService.findById(id);
String fileName;
if (database != null) {
fileName = 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");
}
}
}
/*
* Copyright 2019-2020 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.zq.admin.modules.mnt.rest;
import com.zq.admin.modules.mnt.domain.Deploy;
import com.zq.admin.modules.mnt.domain.DeployHistory;
import com.zq.admin.modules.mnt.service.DeployService;
import com.zq.admin.modules.mnt.service.dto.DeployQueryCriteria;
import com.zq.admin.utils.FileUtil;
import com.zq.logging.annotation.Log;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
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.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("/admin/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<Object> queryDeployData(DeployQueryCriteria criteria, Pageable pageable) {
return new ResponseEntity<>(deployService.queryAll(criteria, pageable), 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 = 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<Object> 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<Object> 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<Object> 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<Object> stopServer(@Validated @RequestBody Deploy resources) {
String result = deployService.stopServer(resources);
return new ResponseEntity<>(result, HttpStatus.OK);
}
}
/*
* Copyright 2019-2020 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.zq.admin.modules.mnt.rest;
import com.zq.admin.modules.mnt.service.DeployHistoryService;
import com.zq.admin.modules.mnt.service.dto.DeployHistoryQueryCriteria;
import com.zq.logging.annotation.Log;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
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 zhanghouying
* @date 2019-08-24
*/
@RestController
@RequiredArgsConstructor
@Api(tags = "运维:部署历史管理")
@RequestMapping("/admin/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<Object> queryDeployHistory(DeployHistoryQueryCriteria criteria, Pageable pageable) {
return new ResponseEntity<>(deployhistoryService.queryAll(criteria, pageable), 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);
}
}
/*
* Copyright 2019-2020 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.zq.admin.modules.mnt.rest;
import com.zq.admin.modules.mnt.domain.ServerDeploy;
import com.zq.admin.modules.mnt.service.ServerDeployService;
import com.zq.admin.modules.mnt.service.dto.ServerDeployQueryCriteria;
import com.zq.logging.annotation.Log;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
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.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("/admin/serverDeploy")
public class ServerDeployController {
private final ServerDeployService serverDeployService;
@ApiOperation("导出服务器数据")
@GetMapping(value = "/download")
@PreAuthorize("@el.check('serverDeploy:list')")
public void exportServerDeploy(HttpServletResponse response, ServerDeployQueryCriteria criteria) throws IOException {
serverDeployService.download(serverDeployService.queryAll(criteria), response);
}
@ApiOperation(value = "查询服务器")
@GetMapping
@PreAuthorize("@el.check('serverDeploy:list')")
public ResponseEntity<Object> queryServerDeploy(ServerDeployQueryCriteria criteria, Pageable pageable) {
return new ResponseEntity<>(serverDeployService.queryAll(criteria, pageable), HttpStatus.OK);
}
@Log("新增服务器")
@ApiOperation(value = "新增服务器")
@PostMapping
@PreAuthorize("@el.check('serverDeploy:add')")
public ResponseEntity<Object> createServerDeploy(@Validated @RequestBody ServerDeploy resources) {
serverDeployService.create(resources);
return new ResponseEntity<>(HttpStatus.CREATED);
}
@Log("修改服务器")
@ApiOperation(value = "修改服务器")
@PutMapping
@PreAuthorize("@el.check('serverDeploy:edit')")
public ResponseEntity<Object> updateServerDeploy(@Validated @RequestBody ServerDeploy resources) {
serverDeployService.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) {
serverDeployService.delete(ids);
return new ResponseEntity<>(HttpStatus.OK);
}
@Log("测试连接服务器")
@ApiOperation(value = "测试连接服务器")
@PostMapping("/testConnect")
@PreAuthorize("@el.check('serverDeploy:add')")
public ResponseEntity<Object> testConnectServerDeploy(@Validated @RequestBody ServerDeploy resources) {
return new ResponseEntity<>(serverDeployService.testConnect(resources), HttpStatus.CREATED);
}
}
/*
* Copyright 2019-2020 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.zq.admin.modules.mnt.service;
import com.zq.admin.modules.mnt.domain.App;
import com.zq.admin.modules.mnt.service.dto.AppDto;
import com.zq.admin.modules.mnt.service.dto.AppQueryCriteria;
import org.springframework.data.domain.Pageable;
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 {
/**
* 分页查询
*
* @param criteria 条件
* @param pageable 分页参数
* @return /
*/
Object queryAll(AppQueryCriteria criteria, Pageable pageable);
/**
* 查询全部数据
*
* @param criteria 条件
* @return /
*/
List<AppDto> queryAll(AppQueryCriteria criteria);
/**
* 根据ID查询
*
* @param id /
* @return /
*/
AppDto findById(Long id);
/**
* 创建
*
* @param resources /
*/
void create(App resources);
/**
* 编辑
*
* @param resources /
*/
void update(App resources);
/**
* 删除
*
* @param ids /
*/
void delete(Set<Long> ids);
/**
* 导出数据
*
* @param queryAll /
* @param response /
* @throws IOException /
*/
void download(List<AppDto> queryAll, HttpServletResponse response) throws IOException;
}
/*
* Copyright 2019-2020 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.zq.admin.modules.mnt.service;
import com.zq.admin.modules.mnt.domain.Database;
import com.zq.admin.modules.mnt.service.dto.DatabaseDto;
import com.zq.admin.modules.mnt.service.dto.DatabaseQueryCriteria;
import org.springframework.data.domain.Pageable;
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 {
/**
* 分页查询
*
* @param criteria 条件
* @param pageable 分页参数
* @return /
*/
Object queryAll(DatabaseQueryCriteria criteria, Pageable pageable);
/**
* 查询全部
*
* @param criteria 条件
* @return /
*/
List<DatabaseDto> queryAll(DatabaseQueryCriteria criteria);
/**
* 根据ID查询
*
* @param id /
* @return /
*/
DatabaseDto findById(String id);
/**
* 创建
*
* @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<DatabaseDto> queryAll, HttpServletResponse response) throws IOException;
}
/*
* Copyright 2019-2020 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.zq.admin.modules.mnt.service;
import com.zq.admin.modules.mnt.domain.DeployHistory;
import com.zq.admin.modules.mnt.service.dto.DeployHistoryDto;
import com.zq.admin.modules.mnt.service.dto.DeployHistoryQueryCriteria;
import org.springframework.data.domain.Pageable;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Set;
/**
* @author zhanghouying
*/
public interface DeployHistoryService {
/**
* 分页查询
*
* @param criteria 条件
* @param pageable 分页参数
* @return /
*/
Object queryAll(DeployHistoryQueryCriteria criteria, Pageable pageable);
/**
* 查询全部
*
* @param criteria 条件
* @return /
*/
List<DeployHistoryDto> queryAll(DeployHistoryQueryCriteria criteria);
/**
* 根据ID查询
*
* @param id /
* @return /
*/
DeployHistoryDto findById(String id);
/**
* 创建
*
* @param resources /
*/
void create(DeployHistory resources);
/**
* 删除
*
* @param ids /
*/
void delete(Set<String> ids);
/**
* 导出数据
*
* @param queryAll /
* @param response /
* @throws IOException /
*/
void download(List<DeployHistoryDto> queryAll, HttpServletResponse response) throws IOException;
}
/*
* Copyright 2019-2020 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.zq.admin.modules.mnt.service;
import com.zq.admin.modules.mnt.domain.Deploy;
import com.zq.admin.modules.mnt.domain.DeployHistory;
import com.zq.admin.modules.mnt.service.dto.DeployDto;
import com.zq.admin.modules.mnt.service.dto.DeployQueryCriteria;
import org.springframework.data.domain.Pageable;
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 {
/**
* 分页查询
*
* @param criteria 条件
* @param pageable 分页参数
* @return /
*/
Object queryAll(DeployQueryCriteria criteria, Pageable pageable);
/**
* 查询全部数据
*
* @param criteria 条件
* @return /
*/
List<DeployDto> queryAll(DeployQueryCriteria criteria);
/**
* 根据ID查询
*
* @param id /
* @return /
*/
DeployDto findById(Long id);
/**
* 创建
*
* @param resources /
*/
void create(Deploy resources);
/**
* 编辑
*
* @param resources /
*/
void update(Deploy resources);
/**
* 删除
*
* @param ids /
*/
void delete(Set<Long> ids);
/**
* 部署文件到服务器
*
* @param fileSavePath 文件路径
* @param appId 应用ID
*/
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<DeployDto> queryAll, HttpServletResponse response) throws IOException;
}
This diff is collapsed. Click to expand it.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment