├── .gitignore ├── README.md ├── byapi-common ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── example │ └── common │ ├── annotation │ ├── LoginCheck.java │ └── MustAdmin.java │ ├── aop │ ├── AuthAspect.java │ └── LoginAspect.java │ ├── config │ ├── CorsConfig.java │ ├── Knife4jConfig.java │ └── MybatisPlusConfig.java │ ├── constant │ ├── CommonConsts.java │ ├── InterfaceConsts.java │ └── UserConsts.java │ ├── enums │ ├── ErrorCode.java │ └── RoleEnum.java │ ├── exception │ ├── BusinessException.java │ └── GlobalExceptionHandler.java │ ├── model │ ├── dto │ │ ├── EmailDto.java │ │ ├── InterfaceAddDto.java │ │ ├── InterfaceInvokeDto.java │ │ ├── InterfacePageDto.java │ │ ├── InterfaceUpdateDto.java │ │ ├── LoginDto.java │ │ ├── RegisterDto.java │ │ ├── UserInterfacePageDto.java │ │ ├── UserInterfaceUpdateDto.java │ │ ├── UserPageDto.java │ │ └── UserUpdateDto.java │ ├── entity │ │ ├── InterfaceInfo.java │ │ ├── User.java │ │ └── UserInterfaceInfo.java │ └── vo │ │ ├── InterfaceVo.java │ │ ├── InvokeCountVo.java │ │ ├── KeyVo.java │ │ └── UserVo.java │ ├── service │ ├── DubboInterfaceService.java │ ├── DubboUserInterfaceService.java │ └── DubboUserService.java │ └── utils │ ├── PageBean.java │ ├── PageRequest.java │ ├── Result.java │ ├── SignUtil.java │ └── TokenBucketLimiter.java ├── byapi-gateway ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── gateway │ │ │ ├── ByapiGatewayApplication.java │ │ │ ├── config │ │ │ └── RedisConfig.java │ │ │ └── filter │ │ │ └── CustomGlobalFilter.java │ └── resources │ │ └── application.yml │ └── test │ └── java │ └── com │ └── example │ └── ByapiGatewayApplicationTests.java ├── byapi-interface ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ ├── ByapiInterfaceApplication.java │ │ │ └── interfaceinfo │ │ │ ├── controller │ │ │ └── InterfaceController.java │ │ │ └── model │ │ │ ├── ImgRes.java │ │ │ └── TalkRes.java │ └── resources │ │ └── application.yml │ └── test │ └── java │ └── com │ └── example │ └── ByapiInterfaceApplicationTests.java ├── byapi-sdk ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── example │ │ ├── client │ │ └── ByApiClient.java │ │ ├── config │ │ └── ByApiConfig.java │ │ └── util │ │ └── SignUtil.java │ └── resources │ └── META-INF │ └── spring.factories ├── byapi-server ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── server │ │ │ ├── ByapiServerApplication.java │ │ │ ├── config │ │ │ └── RedisConfig.java │ │ │ ├── controller │ │ │ ├── InterfaceController.java │ │ │ ├── UserController.java │ │ │ └── UserInterfaceController.java │ │ │ ├── mapper │ │ │ ├── InterfaceMapper.java │ │ │ ├── UserInterfaceMapper.java │ │ │ └── UserMapper.java │ │ │ ├── service │ │ │ ├── InterfaceService.java │ │ │ ├── UserInterfaceService.java │ │ │ ├── UserService.java │ │ │ ├── dubbo │ │ │ │ ├── DubboInterfaceServiceImpl.java │ │ │ │ ├── DubboUserInterfaceServiceImpl.java │ │ │ │ └── DubboUserServiceImpl.java │ │ │ └── impl │ │ │ │ ├── InterfaceServiceImpl.java │ │ │ │ ├── UserInterfaceServiceImpl.java │ │ │ │ └── UserServiceImpl.java │ │ │ └── task │ │ │ └── CacheTask.java │ └── resources │ │ ├── application.yml │ │ ├── images │ │ ├── 2e6b1467dae840a1ba650e682652e07d.png │ │ ├── 7b3b41a5fe5041c78b6fe619a8910373.jpg │ │ └── ebcae2156c3c4489bc1a2cc94c2c5956.png │ │ └── mapper │ │ ├── InterfaceInfoMapper.xml │ │ ├── UserInterfaceMapper.xml │ │ └── UserMapper.xml │ └── test │ └── java │ └── com │ └── example │ └── ByapiServerApplicationTests.java ├── pom.xml └── sql └── byapi.sql /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### By API 2 | 3 | 本项目是一个API接口开放平台,用户可以在线调用接口进行调试,还可以下载SDK,在自己的项目中引入接口代码,实现对接口的远程调用。 4 | 5 |
6 | 7 | 涉及技术: 8 | 9 | + 常用技术框架SpringBoot、MyBatis-Plus 10 | + 数据库MySQL 11 | + Java技术 反射 12 | + 面向切面编程 Spring AOP 13 | + 在线接口文档 Knife4j 14 | + 网关 Gateway 15 | + RPC框架 Dubbo 16 | + 自定义SDK -------------------------------------------------------------------------------- /byapi-common/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.example 8 | byapi-backend 9 | 1.0-SNAPSHOT 10 | 11 | 12 | byapi-common 13 | 14 | 15 | 8 16 | 8 17 | UTF-8 18 | 19 | 20 | 21 | 22 | com.google.code.gson 23 | gson 24 | 2.10.1 25 | 26 | 27 | com.github.xiaoymin 28 | knife4j-spring-boot-starter 29 | 3.0.3 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-aop 34 | 3.0.2 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-web 39 | 2.6.13 40 | 41 | 42 | com.mysql 43 | mysql-connector-j 44 | 8.0.31 45 | 46 | 47 | com.baomidou 48 | mybatis-plus-boot-starter 49 | 3.5.4 50 | 51 | 52 | org.projectlombok 53 | lombok 54 | 1.18.28 55 | 56 | 57 | cn.hutool 58 | hutool-all 59 | 5.8.16 60 | 61 | 62 | org.apache.commons 63 | commons-lang3 64 | 3.12.0 65 | 66 | 67 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/annotation/LoginCheck.java: -------------------------------------------------------------------------------- 1 | package com.example.common.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * 自定义注解,校验用户是否登录 10 | * 11 | * @author by 12 | */ 13 | @Target(ElementType.METHOD) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface LoginCheck { 16 | } 17 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/annotation/MustAdmin.java: -------------------------------------------------------------------------------- 1 | package com.example.common.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * 自定义注解,用于标识需要管理员权限的接口 10 | * 11 | * @author by 12 | */ 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @Target(ElementType.METHOD) 15 | public @interface MustAdmin { 16 | } 17 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/aop/AuthAspect.java: -------------------------------------------------------------------------------- 1 | package com.example.common.aop; 2 | 3 | import com.example.common.constant.UserConsts; 4 | import com.example.common.enums.ErrorCode; 5 | import com.example.common.enums.RoleEnum; 6 | import com.example.common.exception.BusinessException; 7 | import com.example.common.model.vo.UserVo; 8 | import org.aspectj.lang.ProceedingJoinPoint; 9 | import org.aspectj.lang.annotation.Around; 10 | import org.aspectj.lang.annotation.Aspect; 11 | import org.springframework.stereotype.Component; 12 | import org.springframework.web.context.request.RequestAttributes; 13 | import org.springframework.web.context.request.RequestContextHolder; 14 | import org.springframework.web.context.request.ServletRequestAttributes; 15 | 16 | import javax.servlet.http.HttpServletRequest; 17 | 18 | /** 19 | * 权限校验切面类 20 | * 21 | * @author by 22 | */ 23 | @Component 24 | @Aspect 25 | public class AuthAspect { 26 | @Around("@annotation(com.example.common.annotation.MustAdmin))") 27 | public Object authCheck(ProceedingJoinPoint joinPoint) throws Throwable { 28 | //获取请求对象 29 | RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes(); 30 | HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest(); 31 | //获取用户登录态 32 | Object object = request.getSession().getAttribute(UserConsts.USER_LOGIN_STATE); 33 | UserVo userVo = (UserVo) object; 34 | //判断是否为空 35 | if (userVo == null) { 36 | throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR); 37 | } 38 | //判断是否为管理员 39 | String role = userVo.getUserRole(); 40 | if (role.equals(RoleEnum.USER.getRole())) { 41 | throw new BusinessException(ErrorCode.NO_AUTH_ERROR); 42 | } 43 | //放行 44 | return joinPoint.proceed(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/aop/LoginAspect.java: -------------------------------------------------------------------------------- 1 | package com.example.common.aop; 2 | 3 | import com.example.common.constant.UserConsts; 4 | import com.example.common.enums.ErrorCode; 5 | import com.example.common.exception.BusinessException; 6 | import com.example.common.model.vo.UserVo; 7 | import org.aspectj.lang.ProceedingJoinPoint; 8 | import org.aspectj.lang.annotation.Around; 9 | import org.aspectj.lang.annotation.Aspect; 10 | import org.springframework.stereotype.Component; 11 | import org.springframework.web.context.request.RequestAttributes; 12 | import org.springframework.web.context.request.RequestContextHolder; 13 | import org.springframework.web.context.request.ServletRequestAttributes; 14 | 15 | import javax.servlet.http.HttpServletRequest; 16 | 17 | /** 18 | * 登录校验切面类 19 | * 20 | * @author by 21 | */ 22 | @Component 23 | @Aspect 24 | public class LoginAspect { 25 | @Around("@annotation(com.example.common.annotation.LoginCheck)") 26 | public Object loginCheck(ProceedingJoinPoint joinPoint) throws Throwable { 27 | //获取请求对象 28 | RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes(); 29 | HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest(); 30 | //获取登录用户 31 | Object object = request.getSession().getAttribute(UserConsts.USER_LOGIN_STATE); 32 | UserVo userVo = (UserVo) object; 33 | //判断用户是否登录 34 | if (userVo == null) { 35 | throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR); 36 | } 37 | //放行 38 | return joinPoint.proceed(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/config/CorsConfig.java: -------------------------------------------------------------------------------- 1 | package com.example.common.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.web.servlet.config.annotation.CorsRegistry; 5 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 6 | 7 | /** 8 | * @author by 9 | *

10 | * 跨域配置类 11 | */ 12 | @Configuration 13 | public class CorsConfig implements WebMvcConfigurer { 14 | @Override 15 | public void addCorsMappings(CorsRegistry registry) { 16 | // 覆盖所有请求 17 | registry.addMapping("/**") 18 | // 允许发送 Cookie 19 | .allowCredentials(true) 20 | // 放行哪些域名(必须用 patterns,否则 * 会和 allowCredentials 冲突) 21 | .allowedOriginPatterns("*") 22 | .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") 23 | .allowedHeaders("*") 24 | .exposedHeaders("*"); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/config/Knife4jConfig.java: -------------------------------------------------------------------------------- 1 | package com.example.common.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import springfox.documentation.builders.ApiInfoBuilder; 6 | import springfox.documentation.builders.PathSelectors; 7 | import springfox.documentation.builders.RequestHandlerSelectors; 8 | import springfox.documentation.spi.DocumentationType; 9 | import springfox.documentation.spring.web.plugins.Docket; 10 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 11 | 12 | /** 13 | * Knife4j 接口文档配置 14 | * 15 | * @author yupi 16 | */ 17 | @Configuration 18 | @EnableSwagger2 19 | public class Knife4jConfig { 20 | 21 | @Bean 22 | public Docket defaultApi2() { 23 | return new Docket(DocumentationType.SWAGGER_2) 24 | .apiInfo(new ApiInfoBuilder() 25 | .title("API接口开放平台") 26 | .description("API接口开放平台") 27 | .version("1.0") 28 | .build()) 29 | .select() 30 | // 指定 Controller 扫描包路径 31 | .apis(RequestHandlerSelectors.basePackage("com.example.server.controller")) 32 | .paths(PathSelectors.any()) 33 | .build(); 34 | } 35 | } -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/config/MybatisPlusConfig.java: -------------------------------------------------------------------------------- 1 | package com.example.common.config; 2 | 3 | import com.baomidou.mybatisplus.annotation.DbType; 4 | import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; 5 | import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | 9 | /** 10 | * 分页插件 11 | * 12 | * @author by 13 | */ 14 | @Configuration 15 | public class MybatisPlusConfig { 16 | 17 | @Bean 18 | public MybatisPlusInterceptor mybatisPlusInterceptor() { 19 | MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); 20 | //如果配置多个插件,切记分页最后添加 21 | interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); 22 | return interceptor; 23 | } 24 | } -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/constant/CommonConsts.java: -------------------------------------------------------------------------------- 1 | package com.example.common.constant; 2 | 3 | /** 4 | * 通用常量 5 | * 6 | * @author by 7 | */ 8 | public interface CommonConsts { 9 | 10 | String IMAGE_UPLOAD_ERROR = "文件上传错误!"; 11 | String IMAGE_FORMAT_ERROR = "文件格式错误!"; 12 | String IMAGE_READ_ERROR = "文件读取失败!"; 13 | String PAGE_PARAMS_ERROR = "分页参数异常!"; 14 | String EXIST_ERROR = "已开通接口调用权限!无需再次开通!"; 15 | String BODY_KEY = "body-key"; 16 | String SDK_DOWNLOAD_ERROR = "SDK下载失败!"; 17 | String GET_INTERFACE_BY_ID_KEY = "byapi:server:getInterfaceById:%s:%s"; 18 | String LIST_INVOKE_RECORDS_KEY = "byapi:server:listInvokeRecords:%s"; 19 | Integer TIME_GAP = 10 * 60 * 1000; 20 | String NONCE_KEY = "byapi:gateway:filter:nonce"; 21 | String CACHE_SET_ERROR = "缓存设置失败!"; 22 | String CACHE_DEL_ERROR = "缓存删除失败!"; 23 | } 24 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/constant/InterfaceConsts.java: -------------------------------------------------------------------------------- 1 | package com.example.common.constant; 2 | 3 | /** 4 | * @author by 5 | */ 6 | public interface InterfaceConsts { 7 | 8 | String INTERFACE_ONLINE_ERROR = "接口上线中,不能删除!"; 9 | 10 | String INTERFACE_HOST = "http://localhost:9020"; 11 | 12 | String ACCESS_KEY = "accessKey"; 13 | 14 | String SIGN = "sign"; 15 | String NOT_EXIST_ERROR = "接口不存在!"; 16 | String INVOKE_COUNT_ERROR = "接口调用次数不足!"; 17 | String INTERFACE_CLOSE = "接口已关闭!"; 18 | } 19 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/constant/UserConsts.java: -------------------------------------------------------------------------------- 1 | package com.example.common.constant; 2 | 3 | /** 4 | * 用户常量类 5 | * 6 | * @author by 7 | */ 8 | public interface UserConsts { 9 | /** 10 | * 用户登录态 11 | */ 12 | String USER_LOGIN_STATE = "user_login_state"; 13 | Integer USER_NAME_LENGTH = 4; 14 | Integer USER_PASSWORD_LENGTH = 8; 15 | String USER_NAME_ERROR = "用户名长度不能小于4位!"; 16 | String USER_PASSWORD_ERROR = "密码长度不能小于8位!"; 17 | String USER_PARAMS_ERROR = "用户名或密码错误!"; 18 | String PASSWORD_NOT_EQUAL = "密码不一致!"; 19 | String USER_NAME_EXIST = "用户名已经存在!"; 20 | String CODE = "code"; 21 | String EMAIL = "email"; 22 | String VER_CODE = "verCode"; 23 | String DELAY_TASK_ERROR = "延迟任务失败!"; 24 | String SEND_MAIL_ERROR = "发送邮件失败!"; 25 | String EMAIL_PARAMS_ERROR = "邮箱或验证码错误!"; 26 | String EMAIL_EXIST = "邮箱已经存在!"; 27 | String ACCOUNT_FORBIDDEN = "账号已被封禁!"; 28 | } 29 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/enums/ErrorCode.java: -------------------------------------------------------------------------------- 1 | package com.example.common.enums; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | * 错误信息枚举类 7 | * 8 | * @author by 9 | */ 10 | @Getter 11 | public enum ErrorCode { 12 | 13 | /** 14 | * 基本错误信息枚举 15 | */ 16 | PARAMS_ERROR(40000, "请求参数错误"), 17 | NOT_LOGIN_ERROR(40100, "未登录"), 18 | NO_AUTH_ERROR(40101, "无权限"), 19 | FORBIDDEN_ERROR(40300, "禁止访问"), 20 | NOT_FOUND_ERROR(40400, "请求数据不存在"), 21 | SYSTEM_ERROR(50000, "系统内部异常"); 22 | 23 | /** 24 | * 状态码 25 | */ 26 | private final int code; 27 | 28 | /** 29 | * 错误信息 30 | */ 31 | private final String message; 32 | 33 | ErrorCode(int code, String message) { 34 | this.code = code; 35 | this.message = message; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/enums/RoleEnum.java: -------------------------------------------------------------------------------- 1 | package com.example.common.enums; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | * 用户角色枚举 7 | * 8 | * @author by 9 | */ 10 | @Getter 11 | public enum RoleEnum { 12 | 13 | /** 14 | * 管理员 15 | */ 16 | ADMIN("admin"), 17 | /** 18 | * 普通用户 19 | */ 20 | USER("user"); 21 | 22 | private final String role; 23 | 24 | RoleEnum(String role) { 25 | this.role = role; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/exception/BusinessException.java: -------------------------------------------------------------------------------- 1 | package com.example.common.exception; 2 | 3 | import com.example.common.enums.ErrorCode; 4 | import lombok.Getter; 5 | 6 | /** 7 | * 自定义异常 8 | * 9 | * @author by 10 | */ 11 | @Getter 12 | public class BusinessException extends RuntimeException { 13 | 14 | private final Integer code; 15 | 16 | public BusinessException(Integer code, String message) { 17 | super(message); 18 | this.code = code; 19 | } 20 | 21 | public BusinessException(ErrorCode errorCode) { 22 | super(errorCode.getMessage()); 23 | this.code = errorCode.getCode(); 24 | } 25 | 26 | public BusinessException(ErrorCode errorCode, String message) { 27 | super(message); 28 | this.code = errorCode.getCode(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/exception/GlobalExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.example.common.exception; 2 | 3 | import org.springframework.web.bind.annotation.ExceptionHandler; 4 | import org.springframework.web.bind.annotation.RestControllerAdvice; 5 | import com.example.common.utils.Result; 6 | 7 | /** 8 | * 自定义异常处理类 9 | * 10 | * @author by 11 | */ 12 | @RestControllerAdvice 13 | public class GlobalExceptionHandler { 14 | 15 | @ExceptionHandler(BusinessException.class) 16 | public static Result error(BusinessException be) { 17 | return Result.error(be.getCode(), be.getMessage()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/model/dto/EmailDto.java: -------------------------------------------------------------------------------- 1 | package com.example.common.model.dto; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * 邮箱登录请求体 9 | * 10 | * @author by 11 | */ 12 | @Data 13 | public class EmailDto implements Serializable { 14 | /** 15 | * 邮箱 16 | */ 17 | private String email; 18 | /** 19 | * 验证码 20 | */ 21 | private String verCode; 22 | } 23 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/model/dto/InterfaceAddDto.java: -------------------------------------------------------------------------------- 1 | package com.example.common.model.dto; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * @author by 9 | */ 10 | @Data 11 | public class InterfaceAddDto implements Serializable { 12 | /** 13 | * 名称 14 | */ 15 | private String name; 16 | 17 | /** 18 | * 描述 19 | */ 20 | private String description; 21 | 22 | /** 23 | * 接口地址 24 | */ 25 | private String url; 26 | 27 | /** 28 | * 请求类型 29 | */ 30 | private String method; 31 | 32 | /** 33 | * 请求参数 34 | */ 35 | private String requestParams; 36 | 37 | /** 38 | * 请求头 39 | */ 40 | private String requestHeader; 41 | 42 | /** 43 | * 响应头 44 | */ 45 | private String responseHeader; 46 | 47 | /** 48 | * 接口状态(0-关闭,1-开启) 49 | */ 50 | private Integer status; 51 | } 52 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/model/dto/InterfaceInvokeDto.java: -------------------------------------------------------------------------------- 1 | package com.example.common.model.dto; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * 接口调用请求体 9 | * 10 | * @author by 11 | */ 12 | @Data 13 | public class InterfaceInvokeDto implements Serializable { 14 | 15 | /** 16 | * 接口ID 17 | */ 18 | private Long id; 19 | /** 20 | * 请求参数,不必需 21 | */ 22 | private String userRequestParams; 23 | } 24 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/model/dto/InterfacePageDto.java: -------------------------------------------------------------------------------- 1 | package com.example.common.model.dto; 2 | 3 | import com.example.common.utils.PageRequest; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | 7 | /** 8 | * 分页条件请求体 9 | * 10 | * @author by 11 | */ 12 | @EqualsAndHashCode(callSuper = true) 13 | @Data 14 | public class InterfacePageDto extends PageRequest { 15 | /** 16 | * 主键 17 | */ 18 | private Long id; 19 | 20 | /** 21 | * 名称 22 | */ 23 | private String name; 24 | 25 | /** 26 | * 接口地址 27 | */ 28 | private String url; 29 | 30 | /** 31 | * 请求类型 32 | */ 33 | private String method; 34 | 35 | /** 36 | * 接口状态(0-关闭,1-开启) 37 | */ 38 | private Integer status; 39 | } 40 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/model/dto/InterfaceUpdateDto.java: -------------------------------------------------------------------------------- 1 | package com.example.common.model.dto; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * @author by 9 | */ 10 | @Data 11 | public class InterfaceUpdateDto implements Serializable { 12 | /** 13 | * 主键 14 | */ 15 | private Long id; 16 | 17 | /** 18 | * 名称 19 | */ 20 | private String name; 21 | 22 | /** 23 | * 描述 24 | */ 25 | private String description; 26 | 27 | /** 28 | * 接口地址 29 | */ 30 | private String url; 31 | 32 | /** 33 | * 请求类型 34 | */ 35 | private String method; 36 | 37 | /** 38 | * 请求参数 39 | */ 40 | private String requestParams; 41 | 42 | /** 43 | * 请求头 44 | */ 45 | private String requestHeader; 46 | 47 | /** 48 | * 响应头 49 | */ 50 | private String responseHeader; 51 | 52 | /** 53 | * 示例代码 54 | */ 55 | private String codeExample; 56 | } 57 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/model/dto/LoginDto.java: -------------------------------------------------------------------------------- 1 | package com.example.common.model.dto; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * 登录请求体 9 | * 10 | * @author by 11 | */ 12 | @Data 13 | public class LoginDto implements Serializable { 14 | 15 | /** 16 | * 账号 17 | */ 18 | private String userAccount; 19 | /** 20 | * 密码 21 | */ 22 | private String userPassword; 23 | } 24 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/model/dto/RegisterDto.java: -------------------------------------------------------------------------------- 1 | package com.example.common.model.dto; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * 注册请求体 9 | * 10 | * @author by 11 | */ 12 | @Data 13 | public class RegisterDto implements Serializable { 14 | /** 15 | * 账号 16 | */ 17 | private String userAccount; 18 | /** 19 | * 密码 20 | */ 21 | private String userPassword; 22 | /** 23 | * 确认密码 24 | */ 25 | private String confirmPassword; 26 | } 27 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/model/dto/UserInterfacePageDto.java: -------------------------------------------------------------------------------- 1 | package com.example.common.model.dto; 2 | 3 | import com.example.common.utils.PageRequest; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | 7 | /** 8 | * @author by 9 | */ 10 | @EqualsAndHashCode(callSuper = true) 11 | @Data 12 | public class UserInterfacePageDto extends PageRequest { 13 | /** 14 | * 主键 15 | */ 16 | private Long id; 17 | 18 | /** 19 | * 调用接口用户ID 20 | */ 21 | private Long userId; 22 | 23 | /** 24 | * 接口ID 25 | */ 26 | private Long interfaceInfoId; 27 | } 28 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/model/dto/UserInterfaceUpdateDto.java: -------------------------------------------------------------------------------- 1 | package com.example.common.model.dto; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * 用户接口关系更新请求 9 | * 10 | * @author by 11 | */ 12 | @Data 13 | public class UserInterfaceUpdateDto implements Serializable { 14 | /** 15 | * 主键 16 | */ 17 | private Long id; 18 | 19 | /** 20 | * 总调用次数 21 | */ 22 | private Integer totalNum; 23 | 24 | /** 25 | * 剩余调用次数 26 | */ 27 | private Integer leftNum; 28 | } 29 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/model/dto/UserPageDto.java: -------------------------------------------------------------------------------- 1 | package com.example.common.model.dto; 2 | 3 | import com.example.common.utils.PageRequest; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | 7 | /** 8 | * 分页请求体 9 | * 10 | * @author by 11 | */ 12 | @EqualsAndHashCode(callSuper = true) 13 | @Data 14 | public class UserPageDto extends PageRequest { 15 | /** 16 | * id 17 | */ 18 | private Long id; 19 | 20 | /** 21 | * 用户昵称 22 | */ 23 | private String userName; 24 | 25 | /** 26 | * 账号 27 | */ 28 | private String userAccount; 29 | 30 | /** 31 | * 性别(0-男,1-女) 32 | */ 33 | private Integer gender; 34 | 35 | /** 36 | * 用户状态(0-启用,1-禁用) 37 | */ 38 | private Integer status; 39 | } 40 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/model/dto/UserUpdateDto.java: -------------------------------------------------------------------------------- 1 | package com.example.common.model.dto; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * 更新用户请求体 9 | * 10 | * @author by 11 | */ 12 | @Data 13 | public class UserUpdateDto implements Serializable { 14 | /** 15 | * id 16 | */ 17 | private Long id; 18 | 19 | /** 20 | * 用户昵称 21 | */ 22 | private String userName; 23 | 24 | /** 25 | * 账号 26 | */ 27 | private String userAccount; 28 | 29 | /** 30 | * 用户头像 31 | */ 32 | private String userAvatar; 33 | 34 | /** 35 | * 邮箱 36 | */ 37 | private String email; 38 | 39 | /** 40 | * 性别(0-男,1-女) 41 | */ 42 | private Integer gender; 43 | 44 | /** 45 | * 用户状态(0-启用,1-禁用) 46 | */ 47 | private Integer status; 48 | 49 | /** 50 | * 用户角色:user / admin 51 | */ 52 | private String userRole; 53 | } 54 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/model/entity/InterfaceInfo.java: -------------------------------------------------------------------------------- 1 | package com.example.common.model.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.IdType; 4 | import com.baomidou.mybatisplus.annotation.TableField; 5 | import com.baomidou.mybatisplus.annotation.TableId; 6 | import com.baomidou.mybatisplus.annotation.TableLogic; 7 | import com.baomidou.mybatisplus.annotation.TableName; 8 | import lombok.Data; 9 | 10 | import java.io.Serializable; 11 | import java.util.Date; 12 | 13 | /** 14 | * 接口信息 15 | * 16 | * @author by 17 | */ 18 | @TableName(value = "interface") 19 | @Data 20 | public class InterfaceInfo implements Serializable { 21 | /** 22 | * 主键 23 | */ 24 | @TableId(type = IdType.AUTO) 25 | private Long id; 26 | 27 | /** 28 | * 名称 29 | */ 30 | private String name; 31 | 32 | /** 33 | * 描述 34 | */ 35 | private String description; 36 | 37 | /** 38 | * 接口地址 39 | */ 40 | private String url; 41 | 42 | /** 43 | * 请求类型 44 | */ 45 | private String method; 46 | 47 | /** 48 | * 请求参数 49 | */ 50 | private String requestParams; 51 | 52 | /** 53 | * 请求头 54 | */ 55 | private String requestHeader; 56 | 57 | /** 58 | * 响应头 59 | */ 60 | private String responseHeader; 61 | 62 | /** 63 | * 接口状态(0-关闭,1-开启) 64 | */ 65 | private Integer status; 66 | 67 | /** 68 | * 示例代码 69 | */ 70 | private String codeExample; 71 | 72 | /** 73 | * 创建时间 74 | */ 75 | private Date createTime; 76 | 77 | /** 78 | * 更新时间 79 | */ 80 | private Date updateTime; 81 | 82 | /** 83 | * 是否删除(0-未删, 1-已删) 84 | */ 85 | @TableLogic 86 | private Integer isDeleted; 87 | 88 | @TableField(exist = false) 89 | private static final long serialVersionUID = 1L; 90 | } -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/model/entity/User.java: -------------------------------------------------------------------------------- 1 | package com.example.common.model.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.IdType; 4 | import com.baomidou.mybatisplus.annotation.TableField; 5 | import com.baomidou.mybatisplus.annotation.TableId; 6 | import com.baomidou.mybatisplus.annotation.TableLogic; 7 | import com.baomidou.mybatisplus.annotation.TableName; 8 | 9 | import java.io.Serializable; 10 | import java.util.Date; 11 | 12 | import lombok.Data; 13 | 14 | /** 15 | * 用户表 16 | * 17 | * @author by 18 | */ 19 | @TableName(value = "user") 20 | @Data 21 | public class User implements Serializable { 22 | /** 23 | * id 24 | */ 25 | @TableId(type = IdType.AUTO) 26 | private Long id; 27 | 28 | /** 29 | * 用户昵称 30 | */ 31 | private String userName; 32 | 33 | /** 34 | * 账号 35 | */ 36 | private String userAccount; 37 | 38 | /** 39 | * 用户头像 40 | */ 41 | private String userAvatar; 42 | 43 | /** 44 | * 邮箱,用于邮箱登录 45 | */ 46 | private String email; 47 | 48 | /** 49 | * 性别(0-男,1-女) 50 | */ 51 | private Integer gender; 52 | 53 | /** 54 | * 用户状态(0-启用,1-禁用) 55 | */ 56 | private Integer status; 57 | 58 | /** 59 | * 用户角色:user / admin 60 | */ 61 | private String userRole; 62 | 63 | /** 64 | * 密码 65 | */ 66 | private String userPassword; 67 | 68 | /** 69 | * 盐,用于加密 70 | */ 71 | private String salt; 72 | 73 | /** 74 | * accessKey 75 | */ 76 | private String accessKey; 77 | 78 | /** 79 | * secretKey 80 | */ 81 | private String secretKey; 82 | 83 | /** 84 | * 创建时间 85 | */ 86 | private Date createTime; 87 | 88 | /** 89 | * 更新时间 90 | */ 91 | private Date updateTime; 92 | 93 | /** 94 | * 是否删除 95 | */ 96 | @TableLogic 97 | private Integer isDeleted; 98 | 99 | @TableField(exist = false) 100 | private static final long serialVersionUID = 1L; 101 | } -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/model/entity/UserInterfaceInfo.java: -------------------------------------------------------------------------------- 1 | package com.example.common.model.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.IdType; 4 | import com.baomidou.mybatisplus.annotation.TableField; 5 | import com.baomidou.mybatisplus.annotation.TableId; 6 | import com.baomidou.mybatisplus.annotation.TableLogic; 7 | import com.baomidou.mybatisplus.annotation.TableName; 8 | import lombok.Data; 9 | 10 | import java.io.Serializable; 11 | import java.util.Date; 12 | 13 | /** 14 | * 用户调用接口关系 15 | * 16 | * @author by 17 | */ 18 | @TableName(value = "user_interface") 19 | @Data 20 | public class UserInterfaceInfo implements Serializable { 21 | /** 22 | * 主键 23 | */ 24 | @TableId(type = IdType.AUTO) 25 | private Long id; 26 | 27 | /** 28 | * 调用接口用户ID 29 | */ 30 | private Long userId; 31 | 32 | /** 33 | * 接口ID 34 | */ 35 | private Long interfaceId; 36 | 37 | /** 38 | * 总调用次数 39 | */ 40 | private Integer totalNum; 41 | 42 | /** 43 | * 剩余调用次数 44 | */ 45 | private Integer leftNum; 46 | 47 | /** 48 | * 创建时间 49 | */ 50 | private Date createTime; 51 | 52 | /** 53 | * 更新时间 54 | */ 55 | private Date updateTime; 56 | 57 | /** 58 | * 是否删除(0-未删, 1-已删) 59 | */ 60 | @TableLogic 61 | private Integer isDeleted; 62 | 63 | @TableField(exist = false) 64 | private static final long serialVersionUID = 1L; 65 | } -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/model/vo/InterfaceVo.java: -------------------------------------------------------------------------------- 1 | package com.example.common.model.vo; 2 | 3 | import com.example.common.model.entity.InterfaceInfo; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | 7 | /** 8 | * 接口信息返回类 9 | * 10 | * @author by 11 | */ 12 | @EqualsAndHashCode(callSuper = true) 13 | @Data 14 | public class InterfaceVo extends InterfaceInfo { 15 | 16 | /** 17 | * 总调用次数 18 | */ 19 | private Integer totalNum; 20 | 21 | /** 22 | * 剩余调用次数 23 | */ 24 | private Integer leftNum; 25 | } 26 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/model/vo/InvokeCountVo.java: -------------------------------------------------------------------------------- 1 | package com.example.common.model.vo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * 接口调用次数返回类 7 | * 8 | * @author by 9 | */ 10 | @Data 11 | public class InvokeCountVo { 12 | /** 13 | * 接口名称 14 | */ 15 | private String name; 16 | /** 17 | * 调用次数 18 | */ 19 | private Integer count; 20 | } 21 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/model/vo/KeyVo.java: -------------------------------------------------------------------------------- 1 | package com.example.common.model.vo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * 密钥视图对象 7 | * 8 | * @author by 9 | */ 10 | @Data 11 | public class KeyVo { 12 | /** 13 | * 访问密钥 14 | */ 15 | private String accessKey; 16 | /** 17 | * 私钥 18 | */ 19 | private String secretKey; 20 | } 21 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/model/vo/UserVo.java: -------------------------------------------------------------------------------- 1 | package com.example.common.model.vo; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.Date; 6 | 7 | /** 8 | * @author by 9 | */ 10 | @Data 11 | public class UserVo { 12 | /** 13 | * id 14 | */ 15 | private Long id; 16 | 17 | /** 18 | * 用户昵称 19 | */ 20 | private String userName; 21 | 22 | /** 23 | * 账号 24 | */ 25 | private String userAccount; 26 | 27 | /** 28 | * 用户头像 29 | */ 30 | private String userAvatar; 31 | 32 | /** 33 | * 邮箱 34 | */ 35 | private String email; 36 | 37 | /** 38 | * 性别(0-男,1-女) 39 | */ 40 | private Integer gender; 41 | 42 | /** 43 | * 用户角色:user / admin 44 | */ 45 | private String userRole; 46 | 47 | /** 48 | * 创建时间 49 | */ 50 | private Date createTime; 51 | 52 | /** 53 | * 更新时间 54 | */ 55 | private Date updateTime; 56 | } 57 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/service/DubboInterfaceService.java: -------------------------------------------------------------------------------- 1 | package com.example.common.service; 2 | 3 | import com.example.common.model.entity.InterfaceInfo; 4 | 5 | /** 6 | * @author by 7 | */ 8 | public interface DubboInterfaceService { 9 | 10 | /** 11 | * 根据url和method获取接口信息 12 | * 13 | * @param url 接口地址 14 | * @param method 接口方法 15 | * @return 接口信息 16 | */ 17 | public InterfaceInfo getInterfaceInfo(String url, String method); 18 | } 19 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/service/DubboUserInterfaceService.java: -------------------------------------------------------------------------------- 1 | package com.example.common.service; 2 | 3 | /** 4 | * @author by 5 | */ 6 | public interface DubboUserInterfaceService { 7 | 8 | /** 9 | * 统计接口调用次数 10 | * 11 | * @param interfaceId 接口ID 12 | * @param userId 用户ID 13 | */ 14 | void invokeCount(long interfaceId, long userId); 15 | } 16 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/service/DubboUserService.java: -------------------------------------------------------------------------------- 1 | package com.example.common.service; 2 | 3 | import com.example.common.model.entity.User; 4 | 5 | /** 6 | * @author by 7 | */ 8 | public interface DubboUserService { 9 | 10 | /** 11 | * 根据accessKey获取用户信息 12 | * 13 | * @param accessKey 签名 14 | * @return 用户信息 15 | */ 16 | public User getInvokeUser(String accessKey); 17 | } 18 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/utils/PageBean.java: -------------------------------------------------------------------------------- 1 | package com.example.common.utils; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * 分页工具类 11 | * 12 | * @param 13 | * @author by 14 | */ 15 | @Data 16 | @NoArgsConstructor 17 | @AllArgsConstructor(staticName = "of") 18 | public class PageBean { 19 | /** 20 | * 总条数 21 | */ 22 | private Long total; 23 | /** 24 | * 总记录数 25 | */ 26 | private List records; 27 | } 28 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/utils/PageRequest.java: -------------------------------------------------------------------------------- 1 | package com.example.common.utils; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * 通用分页参数 9 | * 10 | * @author by 11 | */ 12 | @Data 13 | public class PageRequest implements Serializable { 14 | /** 15 | * 当前页码 16 | */ 17 | private Integer current = 1; 18 | /** 19 | * 每页记录数 20 | */ 21 | private Integer pageSize = 10; 22 | } 23 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/utils/Result.java: -------------------------------------------------------------------------------- 1 | package com.example.common.utils; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * 返回结果工具类 7 | * 8 | * @author by 9 | */ 10 | @Data 11 | public class Result { 12 | 13 | /** 14 | * 响应码 15 | */ 16 | private Integer code; 17 | /** 18 | * 响应数据 19 | */ 20 | private T data; 21 | /** 22 | * 响应信息 23 | */ 24 | private String message; 25 | 26 | /** 27 | * 响应成功,不带数据 28 | */ 29 | public static Result success() { 30 | Result result = new Result<>(); 31 | result.setCode(200); 32 | result.setData(null); 33 | result.setMessage("请求成功"); 34 | return result; 35 | } 36 | 37 | /** 38 | * 响应成功,带返回数据 39 | */ 40 | public static Result success(T data) { 41 | Result result = new Result<>(); 42 | result.setCode(200); 43 | result.setData(data); 44 | result.setMessage("请求成功"); 45 | return result; 46 | } 47 | 48 | /** 49 | * 响应失败 50 | */ 51 | public static Result error(Integer code, String message) { 52 | Result result = new Result<>(); 53 | result.setCode(code); 54 | result.setData(null); 55 | result.setMessage(message); 56 | return result; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/utils/SignUtil.java: -------------------------------------------------------------------------------- 1 | package com.example.common.utils; 2 | 3 | import cn.hutool.crypto.digest.DigestAlgorithm; 4 | import cn.hutool.crypto.digest.Digester; 5 | 6 | /** 7 | * 签名工具类 8 | * 9 | * @author by 10 | */ 11 | public class SignUtil { 12 | 13 | public static String generateSign(String body, String secretKey) { 14 | String newSecret = body + "-" + secretKey; 15 | Digester digester = new Digester(DigestAlgorithm.SHA256); 16 | return digester.digestHex(newSecret); 17 | } 18 | } -------------------------------------------------------------------------------- /byapi-common/src/main/java/com/example/common/utils/TokenBucketLimiter.java: -------------------------------------------------------------------------------- 1 | package com.example.common.utils; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import java.util.concurrent.atomic.AtomicInteger; 6 | 7 | /** 8 | * 令牌桶算法实现类 9 | * 10 | * @author by 11 | */ 12 | @Component 13 | public class TokenBucketLimiter { 14 | /** 15 | * 上一次获取令牌的时间 16 | */ 17 | public long lastTime = System.currentTimeMillis(); 18 | /** 19 | * 令牌桶的容量 20 | */ 21 | public int capacity = 4; 22 | /** 23 | * 生成令牌的速率(每秒2个) 24 | */ 25 | public int rate = 2; 26 | /** 27 | * 当前桶里的令牌数量 28 | */ 29 | public AtomicInteger tokens = new AtomicInteger(0); 30 | 31 | /** 32 | * 令牌桶算法实现限流,默认每次请求消耗一个令牌 33 | * 34 | * @return 是否限流 35 | */ 36 | 37 | public synchronized boolean isLimited() { 38 | //获取当前时间 39 | long currentTime = System.currentTimeMillis(); 40 | //计算时间间隔(单位为ms) 41 | long gap = currentTime - lastTime; 42 | //计算在这段时间内生成的令牌 43 | int generateCount = (int) (gap / 1000 * rate); 44 | //计算可能的令牌总数 45 | int allTokensCount = tokens.get() + generateCount; 46 | //设置令牌桶里的令牌数量,这里要取总数量与桶容量之间的最小值 47 | tokens.set(Math.min(capacity, allTokensCount)); 48 | //开始获取令牌 49 | if (tokens.get() < 1) { 50 | //当前桶里令牌数量小于1个,进行限流 51 | return true; 52 | } 53 | //令牌数量足够,领取令牌,重新计算上一次获取令牌的时间 54 | tokens.decrementAndGet(); 55 | lastTime = currentTime; 56 | return false; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /byapi-gateway/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | com.example 6 | byapi-gateway 7 | 0.0.1-SNAPSHOT 8 | byapi-gateway 9 | byapi-gateway 10 | 11 | 1.8 12 | UTF-8 13 | UTF-8 14 | 2.6.13 15 | 2021.0.5 16 | 17 | 18 | 19 | org.springframework.boot 20 | spring-boot-starter-data-redis 21 | 22 | 23 | org.apache.dubbo 24 | dubbo 25 | 3.0.9 26 | 27 | 28 | com.alibaba.nacos 29 | nacos-client 30 | 2.1.0 31 | 32 | 33 | org.example 34 | byapi-common 35 | 1.0-SNAPSHOT 36 | 37 | 38 | org.springframework.cloud 39 | spring-cloud-starter-gateway 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-starter-test 44 | test 45 | 46 | 47 | 48 | 49 | 50 | org.springframework.cloud 51 | spring-cloud-dependencies 52 | ${spring-cloud.version} 53 | pom 54 | import 55 | 56 | 57 | org.springframework.boot 58 | spring-boot-dependencies 59 | ${spring-boot.version} 60 | pom 61 | import 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | org.apache.maven.plugins 70 | maven-compiler-plugin 71 | 3.8.1 72 | 73 | 1.8 74 | 1.8 75 | UTF-8 76 | 77 | 78 | 79 | org.springframework.boot 80 | spring-boot-maven-plugin 81 | ${spring-boot.version} 82 | 83 | com.example.gateway.ByapiGatewayApplication 84 | true 85 | 86 | 87 | 88 | repackage 89 | 90 | repackage 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /byapi-gateway/src/main/java/com/example/gateway/ByapiGatewayApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.gateway; 2 | 3 | import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; 7 | 8 | /** 9 | * @author by 10 | */ 11 | @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class},scanBasePackages = {"com.example.gateway","com.example.common"}) 12 | @EnableDubbo 13 | public class ByapiGatewayApplication { 14 | 15 | public static void main(String[] args) { 16 | SpringApplication.run(ByapiGatewayApplication.class, args); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /byapi-gateway/src/main/java/com/example/gateway/config/RedisConfig.java: -------------------------------------------------------------------------------- 1 | package com.example.gateway.config; 2 | 3 | import com.fasterxml.jackson.annotation.JsonAutoDetect; 4 | import com.fasterxml.jackson.annotation.JsonTypeInfo; 5 | import com.fasterxml.jackson.annotation.PropertyAccessor; 6 | import com.fasterxml.jackson.databind.ObjectMapper; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | import org.springframework.data.redis.connection.RedisConnectionFactory; 10 | import org.springframework.data.redis.core.RedisTemplate; 11 | import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; 12 | import org.springframework.data.redis.serializer.StringRedisSerializer; 13 | 14 | /** 15 | * Redis配置类 16 | * 17 | * @author by 18 | */ 19 | @Configuration 20 | public class RedisConfig { 21 | 22 | @Bean 23 | public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { 24 | RedisTemplate template = new RedisTemplate<>(); 25 | template.setConnectionFactory(redisConnectionFactory); 26 | 27 | //配置redis序列化方式 28 | Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class); 29 | ObjectMapper om = new ObjectMapper(); 30 | om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); 31 | om.activateDefaultTyping(om.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY); 32 | jackson2JsonRedisSerializer.setObjectMapper(om); 33 | StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); 34 | 35 | // key采用String的序列化方式 36 | template.setKeySerializer(stringRedisSerializer); 37 | // hash的key也采用String的序列化方式 38 | template.setHashKeySerializer(stringRedisSerializer); 39 | // value序列化方式采用jackson 40 | template.setValueSerializer(jackson2JsonRedisSerializer); 41 | // hash的value序列化方式采用jackson 42 | template.setHashValueSerializer(jackson2JsonRedisSerializer); 43 | template.afterPropertiesSet(); 44 | 45 | return template; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /byapi-gateway/src/main/java/com/example/gateway/filter/CustomGlobalFilter.java: -------------------------------------------------------------------------------- 1 | package com.example.gateway.filter; 2 | 3 | import cn.hutool.core.util.StrUtil; 4 | import com.example.common.constant.CommonConsts; 5 | import com.example.common.constant.InterfaceConsts; 6 | import com.example.common.enums.ErrorCode; 7 | import com.example.common.exception.BusinessException; 8 | import com.example.common.model.entity.InterfaceInfo; 9 | import com.example.common.model.entity.User; 10 | import com.example.common.service.DubboInterfaceService; 11 | import com.example.common.service.DubboUserInterfaceService; 12 | import com.example.common.service.DubboUserService; 13 | import com.example.common.utils.SignUtil; 14 | import com.example.common.utils.TokenBucketLimiter; 15 | import lombok.extern.slf4j.Slf4j; 16 | import org.apache.dubbo.config.annotation.DubboReference; 17 | import org.reactivestreams.Publisher; 18 | import org.springframework.cloud.gateway.filter.GatewayFilterChain; 19 | import org.springframework.cloud.gateway.filter.GlobalFilter; 20 | import org.springframework.core.Ordered; 21 | import org.springframework.core.io.buffer.DataBuffer; 22 | import org.springframework.core.io.buffer.DataBufferFactory; 23 | import org.springframework.core.io.buffer.DataBufferUtils; 24 | import org.springframework.data.redis.core.RedisTemplate; 25 | import org.springframework.data.redis.core.ZSetOperations; 26 | import org.springframework.http.HttpHeaders; 27 | import org.springframework.http.HttpStatus; 28 | import org.springframework.http.server.reactive.ServerHttpRequest; 29 | import org.springframework.http.server.reactive.ServerHttpResponse; 30 | import org.springframework.http.server.reactive.ServerHttpResponseDecorator; 31 | import org.springframework.stereotype.Component; 32 | import org.springframework.web.server.ServerWebExchange; 33 | import reactor.core.publisher.Flux; 34 | import reactor.core.publisher.Mono; 35 | 36 | import javax.annotation.Resource; 37 | import java.nio.charset.StandardCharsets; 38 | 39 | /** 40 | * 自定义全局过滤器 41 | * 42 | * @author by 43 | */ 44 | @Component 45 | @Slf4j 46 | public class CustomGlobalFilter implements GlobalFilter, Ordered { 47 | 48 | @DubboReference 49 | private DubboUserService dubboUserService; 50 | @DubboReference 51 | private DubboInterfaceService dubboInterfaceService; 52 | @DubboReference 53 | private DubboUserInterfaceService dubboUserInterfaceService; 54 | @Resource 55 | private RedisTemplate redisTemplate; 56 | @Resource 57 | private TokenBucketLimiter tokenBucketLimiter; 58 | 59 | @Override 60 | public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { 61 | //获取请求数据 62 | ServerHttpRequest request = exchange.getRequest(); 63 | //获取接口地址 64 | String url = InterfaceConsts.INTERFACE_HOST + request.getPath().value(); 65 | //获取接口方法 66 | String method = request.getMethodValue(); 67 | //打印请求日志 68 | log.info("请求标识:" + request.getId()); 69 | log.info("请求路径:" + url); 70 | log.info("请求方法:" + method); 71 | log.info("请求参数:" + request.getQueryParams()); 72 | //用户鉴权 73 | //获取请求头 74 | HttpHeaders headers = request.getHeaders(); 75 | //检查时间戳和随机数防止请求重放 76 | String timestamp = headers.getFirst("timestamp"); 77 | String nonce = headers.getFirst("nonce"); 78 | //判断请求携带的时间戳和当前时间是否间隔十分钟之内 79 | long currentTimeMillis = System.currentTimeMillis(); 80 | if (StrUtil.isBlank(timestamp)) { 81 | return handleNoAuth(exchange.getResponse()); 82 | } 83 | if (Math.abs(currentTimeMillis - Long.parseLong(timestamp)) > CommonConsts.TIME_GAP) { 84 | return handleNoAuth(exchange.getResponse()); 85 | } 86 | //检查随机数是否重复 87 | ZSetOperations zSetOperations = redisTemplate.opsForZSet(); 88 | if (nonce == null) { 89 | return handleNoAuth(exchange.getResponse()); 90 | } 91 | if (Boolean.FALSE.equals(redisTemplate.hasKey(CommonConsts.NONCE_KEY))) { 92 | //初始化随机数集合 93 | //保存随机数和时间戳再通过定时任务删除过期随机数 94 | addNonceToSet(zSetOperations, nonce); 95 | } else { 96 | //判断随机数是否存在 97 | Double score = zSetOperations.score(CommonConsts.NONCE_KEY, nonce); 98 | //随机数存在则让请求失效 99 | if (score != null) { 100 | return handleNoAuth(exchange.getResponse()); 101 | } 102 | //保存随机数 103 | addNonceToSet(zSetOperations, nonce); 104 | } 105 | String accessKey = headers.getFirst(InterfaceConsts.ACCESS_KEY); 106 | User user = null; 107 | try { 108 | user = dubboUserService.getInvokeUser(accessKey); 109 | } catch (Exception e) { 110 | log.info("invokeUser error", e); 111 | } 112 | //判断用户是否存在 113 | if (user == null) { 114 | return handleNoAuth(exchange.getResponse()); 115 | } 116 | //校验密钥 117 | String headerSign = headers.getFirst(InterfaceConsts.SIGN); 118 | String sign = SignUtil.generateSign(CommonConsts.BODY_KEY, user.getSecretKey()); 119 | if (!sign.equals(headerSign)) { 120 | return handleNoAuth(exchange.getResponse()); 121 | } 122 | //利用令牌桶算法对请求进行限流 123 | if (tokenBucketLimiter.isLimited()) { 124 | return handleNoAuth(exchange.getResponse()); 125 | } 126 | //判断接口是否存在 127 | InterfaceInfo interfaceInfo = null; 128 | try { 129 | interfaceInfo = dubboInterfaceService.getInterfaceInfo(url, method); 130 | } catch (Exception e) { 131 | log.info("invokeInterfaceInfo error", e); 132 | } 133 | if (interfaceInfo == null) { 134 | return handleInvokeError(exchange.getResponse()); 135 | } 136 | return handleResponse(exchange, chain, interfaceInfo.getId(), user.getId()); 137 | } 138 | 139 | /** 140 | * 保存随机数 141 | * 142 | * @param zSetOperations zSet集合 143 | * @param nonce 随机数 144 | */ 145 | private void addNonceToSet(ZSetOperations zSetOperations, String nonce) { 146 | try { 147 | zSetOperations.add(CommonConsts.NONCE_KEY, nonce, System.currentTimeMillis() / 1000.0); 148 | } catch (Exception e) { 149 | log.error("redis set key error", e); 150 | throw new BusinessException(ErrorCode.PARAMS_ERROR, CommonConsts.CACHE_SET_ERROR); 151 | } 152 | } 153 | 154 | /** 155 | * 获取响应结果,打印响应日志 156 | * 157 | * @param exchange exchange 158 | * @param chain chain 159 | * @param interfaceInfoId 接口ID 160 | * @param userId 用户ID 161 | * @return 获取响应结果 162 | */ 163 | private Mono handleResponse(ServerWebExchange exchange, GatewayFilterChain chain, long interfaceInfoId, long userId) { 164 | try { 165 | ServerHttpResponse originalResponse = exchange.getResponse(); 166 | //缓存数据的工厂 167 | DataBufferFactory bufferFactory = originalResponse.bufferFactory(); 168 | //取出响应码 169 | HttpStatus statusCode = originalResponse.getStatusCode(); 170 | if (statusCode != HttpStatus.OK) { 171 | //降级处理返回数据 172 | return chain.filter(exchange); 173 | } 174 | //定义一个响应结果装饰器 175 | ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) { 176 | //等调用完转发的接口才会执行 177 | @Override 178 | public Mono writeWith(Publisher body) { 179 | if (body instanceof Flux) { 180 | Flux fluxBody = Flux.from(body); 181 | return super.writeWith(fluxBody.map(dataBuffer -> { 182 | try { 183 | dubboUserInterfaceService.invokeCount(interfaceInfoId, userId); 184 | } catch (Exception e) { 185 | log.error("invokeCount error", e); 186 | } 187 | byte[] content = new byte[dataBuffer.readableByteCount()]; 188 | dataBuffer.read(content); 189 | //释放掉内存 190 | DataBufferUtils.release(dataBuffer); 191 | // 构建返回日志 192 | //响应数据 193 | String responseData = new String(content, StandardCharsets.UTF_8); 194 | log.info("响应结果:" + responseData); 195 | return bufferFactory.wrap(content); 196 | })); 197 | } else { 198 | log.error("<-- {} 响应code异常", getStatusCode()); 199 | } 200 | return super.writeWith(body); 201 | } 202 | }; 203 | //转发请求,执行调用的接口 204 | return chain.filter(exchange.mutate().response(decoratedResponse).build()); 205 | } catch (Exception e) { 206 | log.error("gateway log exception.\n" + e); 207 | return chain.filter(exchange); 208 | } 209 | } 210 | 211 | @Override 212 | public int getOrder() { 213 | return -1; 214 | } 215 | 216 | public Mono handleNoAuth(ServerHttpResponse response) { 217 | response.setStatusCode(HttpStatus.FORBIDDEN); 218 | return response.setComplete(); 219 | } 220 | 221 | public Mono handleInvokeError(ServerHttpResponse response) { 222 | response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR); 223 | return response.setComplete(); 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /byapi-gateway/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 9010 3 | spring: 4 | main: 5 | web-application-type: reactive 6 | cloud: 7 | gateway: 8 | routes: 9 | - id: byapi-interface 10 | uri: http://localhost:9020 11 | predicates: 12 | - Path=/** 13 | redis: 14 | host: localhost 15 | port: 6379 16 | 17 | 18 | 19 | dubbo: 20 | application: 21 | name: consumer 22 | protocol: 23 | name: dubbo 24 | port: -1 25 | registry: 26 | address: nacos://localhost:8848 27 | -------------------------------------------------------------------------------- /byapi-gateway/src/test/java/com/example/ByapiGatewayApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ByapiGatewayApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /byapi-interface/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | com.example 6 | byapi-interface 7 | 0.0.1-SNAPSHOT 8 | byapi-interface 9 | byapi-interface 10 | 11 | 1.8 12 | UTF-8 13 | UTF-8 14 | 2.6.13 15 | 16 | 17 | 18 | org.projectlombok 19 | lombok 20 | 21 | 22 | com.google.code.gson 23 | gson 24 | 25 | 26 | cn.hutool 27 | hutool-all 28 | 5.8.16 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-starter-web 33 | 34 | 35 | org.springframework.boot 36 | spring-boot-starter 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter-test 41 | test 42 | 43 | 44 | 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-dependencies 49 | ${spring-boot.version} 50 | pom 51 | import 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | org.apache.maven.plugins 60 | maven-compiler-plugin 61 | 3.8.1 62 | 63 | 1.8 64 | 1.8 65 | UTF-8 66 | 67 | 68 | 69 | org.springframework.boot 70 | spring-boot-maven-plugin 71 | ${spring-boot.version} 72 | 73 | com.example.ByapiInterfaceApplication 74 | true 75 | 76 | 77 | 78 | repackage 79 | 80 | repackage 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /byapi-interface/src/main/java/com/example/ByapiInterfaceApplication.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | /** 7 | * @author by 8 | */ 9 | @SpringBootApplication 10 | public class ByapiInterfaceApplication { 11 | 12 | public static void main(String[] args) { 13 | SpringApplication.run(ByapiInterfaceApplication.class, args); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /byapi-interface/src/main/java/com/example/interfaceinfo/controller/InterfaceController.java: -------------------------------------------------------------------------------- 1 | package com.example.interfaceinfo.controller; 2 | 3 | import cn.hutool.http.HttpRequest; 4 | import com.example.interfaceinfo.model.ImgRes; 5 | import com.example.interfaceinfo.model.TalkRes; 6 | import com.google.gson.Gson; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | /** 12 | * 实际提供数据的接口 13 | * 14 | * @author by 15 | */ 16 | @RestController 17 | @RequestMapping("/actual") 18 | public class InterfaceController { 19 | 20 | @GetMapping("/get/name") 21 | public String getName(String name) { 22 | return "你好," + name; 23 | } 24 | 25 | @GetMapping("/random/imageUrl") 26 | public String randomImageUrl() { 27 | //获取随机图片 28 | HttpRequest request = HttpRequest.get("https://api.btstu.cn/sjbz/api.php?format=json"); 29 | String json = request.execute().body(); 30 | //解析JSON 31 | Gson gson = new Gson(); 32 | ImgRes imgRes = gson.fromJson(json, ImgRes.class); 33 | return imgRes.getImgurl(); 34 | } 35 | 36 | @GetMapping("/random/loveTalk") 37 | public String randomLoveTalk() { 38 | //获取随机土味情话 39 | HttpRequest request = HttpRequest.get("https://api.uomg.com/api/rand.qinghua?format=json"); 40 | String json = request.execute().body(); 41 | //解析JSON 42 | Gson gson = new Gson(); 43 | TalkRes talkRes = gson.fromJson(json, TalkRes.class); 44 | return talkRes.getContent(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /byapi-interface/src/main/java/com/example/interfaceinfo/model/ImgRes.java: -------------------------------------------------------------------------------- 1 | package com.example.interfaceinfo.model; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @author by 7 | */ 8 | @Data 9 | public class ImgRes { 10 | /** 11 | * 响应码 12 | */ 13 | private Integer code; 14 | /** 15 | * 图片地址 16 | */ 17 | private String imgurl; 18 | /** 19 | * 宽度 20 | */ 21 | private Integer width; 22 | /** 23 | * 高度 24 | */ 25 | private Integer height; 26 | } 27 | -------------------------------------------------------------------------------- /byapi-interface/src/main/java/com/example/interfaceinfo/model/TalkRes.java: -------------------------------------------------------------------------------- 1 | package com.example.interfaceinfo.model; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @author by 7 | */ 8 | @Data 9 | public class TalkRes { 10 | /** 11 | * 状态码 12 | */ 13 | private String code; 14 | /** 15 | * 文本内容 16 | */ 17 | private String content; 18 | /** 19 | * 错误提示信息 20 | */ 21 | private String msg; 22 | } 23 | -------------------------------------------------------------------------------- /byapi-interface/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 9020 -------------------------------------------------------------------------------- /byapi-interface/src/test/java/com/example/ByapiInterfaceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ByapiInterfaceApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /byapi-sdk/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | com.example 6 | byapi-sdk 7 | 0.0.1-SNAPSHOT 8 | byapi-sdk 9 | byapi-sdk 10 | 11 | 1.8 12 | UTF-8 13 | UTF-8 14 | 2.6.13 15 | 16 | 17 | 18 | cn.hutool 19 | hutool-all 20 | 5.8.16 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter 25 | 26 | 27 | org.projectlombok 28 | lombok 29 | true 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-test 34 | test 35 | 36 | 37 | 38 | 39 | 40 | org.springframework.boot 41 | spring-boot-dependencies 42 | ${spring-boot.version} 43 | pom 44 | import 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /byapi-sdk/src/main/java/com/example/client/ByApiClient.java: -------------------------------------------------------------------------------- 1 | package com.example.client; 2 | 3 | import cn.hutool.core.util.RandomUtil; 4 | import cn.hutool.http.HttpRequest; 5 | import com.example.util.SignUtil; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | /** 11 | * sdk客户端 12 | * 13 | * @author by 14 | */ 15 | public class ByApiClient { 16 | 17 | /** 18 | * 签名标识 19 | */ 20 | private final String accessKey; 21 | /** 22 | * 密钥 23 | */ 24 | private final String secretKey; 25 | 26 | /** 27 | * 网关地址 28 | */ 29 | private static final String GATEWAY_HOST = "http://localhost:9010"; 30 | 31 | /** 32 | * 加密钥匙 33 | */ 34 | public static final String BODY_KEY = "body-key"; 35 | 36 | public ByApiClient(String accessKey, String secretKey) { 37 | this.accessKey = accessKey; 38 | this.secretKey = secretKey; 39 | } 40 | 41 | /** 42 | * 获取输入的名称 43 | * 44 | * @param name 名称 45 | * @return 名称 46 | */ 47 | public String getName(String name) { 48 | //添加请求头 49 | Map headerMap = this.getHeaderMap(BODY_KEY); 50 | //发送请求 51 | HttpRequest httpRequest = HttpRequest.get(GATEWAY_HOST + "/actual/get/name") 52 | .form("name", name) 53 | .addHeaders(headerMap); 54 | //返回请求数据 55 | return httpRequest.execute().body(); 56 | } 57 | 58 | /** 59 | * 随机生成图片 60 | * 61 | * @return 图片地址 62 | */ 63 | public String randomImageUrl() { 64 | //添加请求头 65 | Map headerMap = this.getHeaderMap(BODY_KEY); 66 | //发送请求 67 | HttpRequest httpRequest = HttpRequest.get(GATEWAY_HOST + "/actual/random/imageUrl") 68 | .addHeaders(headerMap); 69 | //返回请求数据 70 | return httpRequest.execute().body(); 71 | } 72 | 73 | /** 74 | * 随机生成土味情话 75 | * 76 | * @return 土味情话 77 | */ 78 | public String randomLoveTalk() { 79 | //添加请求头 80 | Map headerMap = this.getHeaderMap(BODY_KEY); 81 | //发送请求 82 | HttpRequest httpRequest = HttpRequest.get(GATEWAY_HOST + "/actual/random/loveTalk") 83 | .addHeaders(headerMap); 84 | //返回请求数据 85 | return httpRequest.execute().body(); 86 | } 87 | 88 | 89 | public Map getHeaderMap(String bodyKey) { 90 | Map map = new HashMap<>(3); 91 | //凭证 92 | map.put("accessKey", accessKey); 93 | //签名 94 | map.put("sign", SignUtil.generateSign(bodyKey, secretKey)); 95 | //随机数和时间戳用于防止请求重放 96 | //添加随机数 97 | map.put("nonce", RandomUtil.randomNumbers(4)); 98 | //添加时间戳 99 | map.put("timestamp", String.valueOf(System.currentTimeMillis())); 100 | return map; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /byapi-sdk/src/main/java/com/example/config/ByApiConfig.java: -------------------------------------------------------------------------------- 1 | package com.example.config; 2 | 3 | import com.example.client.ByApiClient; 4 | import lombok.Data; 5 | import org.springframework.boot.context.properties.ConfigurationProperties; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.ComponentScan; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | /** 11 | * sdk配置类 12 | * 13 | * @author by 14 | */ 15 | @Configuration 16 | @ConfigurationProperties(prefix = "byapi.client") 17 | @Data 18 | @ComponentScan 19 | public class ByApiConfig { 20 | 21 | private String accessKey; 22 | private String secretKey; 23 | 24 | @Bean 25 | public ByApiClient byApiClient() { 26 | return new ByApiClient(accessKey, secretKey); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /byapi-sdk/src/main/java/com/example/util/SignUtil.java: -------------------------------------------------------------------------------- 1 | package com.example.util; 2 | 3 | import cn.hutool.crypto.digest.DigestAlgorithm; 4 | import cn.hutool.crypto.digest.Digester; 5 | 6 | /** 7 | * 签名工具类 8 | * 9 | * @author by 10 | */ 11 | public class SignUtil { 12 | 13 | public static String generateSign(String body, String secretKey) { 14 | String newSecret = body + "-" + secretKey; 15 | Digester digester = new Digester(DigestAlgorithm.SHA256); 16 | return digester.digestHex(newSecret); 17 | } 18 | } -------------------------------------------------------------------------------- /byapi-sdk/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.example.config.ByApiConfig -------------------------------------------------------------------------------- /byapi-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | com.example 6 | byapi-server 7 | 0.0.1-SNAPSHOT 8 | byapi-server 9 | byapi-server 10 | 11 | 1.8 12 | UTF-8 13 | UTF-8 14 | 2.6.13 15 | 16 | 17 | 18 | org.springframework.boot 19 | spring-boot-starter-data-redis 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-mail 24 | 25 | 26 | org.apache.dubbo 27 | dubbo 28 | 3.0.9 29 | 30 | 31 | com.alibaba.nacos 32 | nacos-client 33 | 2.1.0 34 | 35 | 36 | com.example 37 | byapi-sdk 38 | 0.0.1-SNAPSHOT 39 | 40 | 41 | org.example 42 | byapi-common 43 | 1.0-SNAPSHOT 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-starter 48 | 49 | 50 | org.springframework.boot 51 | spring-boot-starter-test 52 | test 53 | 54 | 55 | 56 | 57 | 58 | org.springframework.boot 59 | spring-boot-dependencies 60 | ${spring-boot.version} 61 | pom 62 | import 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | org.apache.maven.plugins 71 | maven-compiler-plugin 72 | 3.8.1 73 | 74 | 1.8 75 | 1.8 76 | UTF-8 77 | 78 | 79 | 80 | org.springframework.boot 81 | spring-boot-maven-plugin 82 | ${spring-boot.version} 83 | 84 | com.example.server.ByapiServerApplication 85 | true 86 | 87 | 88 | 89 | repackage 90 | 91 | repackage 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /byapi-server/src/main/java/com/example/server/ByapiServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.server; 2 | 3 | import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.scheduling.annotation.EnableScheduling; 7 | 8 | /** 9 | * @author by 10 | */ 11 | @SpringBootApplication(scanBasePackages = {"com.example.common", "com.example.server"}) 12 | @EnableDubbo 13 | @EnableScheduling 14 | public class ByapiServerApplication { 15 | 16 | public static void main(String[] args) { 17 | SpringApplication.run(ByapiServerApplication.class, args); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /byapi-server/src/main/java/com/example/server/config/RedisConfig.java: -------------------------------------------------------------------------------- 1 | package com.example.server.config; 2 | 3 | import com.fasterxml.jackson.annotation.JsonAutoDetect; 4 | import com.fasterxml.jackson.annotation.JsonTypeInfo; 5 | import com.fasterxml.jackson.annotation.PropertyAccessor; 6 | import com.fasterxml.jackson.databind.ObjectMapper; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | import org.springframework.data.redis.connection.RedisConnectionFactory; 10 | import org.springframework.data.redis.core.RedisTemplate; 11 | import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; 12 | import org.springframework.data.redis.serializer.StringRedisSerializer; 13 | 14 | /** 15 | * Redis配置类 16 | * 17 | * @author by 18 | */ 19 | @Configuration 20 | public class RedisConfig { 21 | 22 | @Bean 23 | public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { 24 | RedisTemplate template = new RedisTemplate<>(); 25 | template.setConnectionFactory(redisConnectionFactory); 26 | 27 | //配置redis序列化方式 28 | Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class); 29 | ObjectMapper om = new ObjectMapper(); 30 | om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); 31 | om.activateDefaultTyping(om.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY); 32 | jackson2JsonRedisSerializer.setObjectMapper(om); 33 | StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); 34 | 35 | // key采用String的序列化方式 36 | template.setKeySerializer(stringRedisSerializer); 37 | // hash的key也采用String的序列化方式 38 | template.setHashKeySerializer(stringRedisSerializer); 39 | // value序列化方式采用jackson 40 | template.setValueSerializer(jackson2JsonRedisSerializer); 41 | // hash的value序列化方式采用jackson 42 | template.setHashValueSerializer(jackson2JsonRedisSerializer); 43 | template.afterPropertiesSet(); 44 | 45 | return template; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /byapi-server/src/main/java/com/example/server/controller/InterfaceController.java: -------------------------------------------------------------------------------- 1 | package com.example.server.controller; 2 | 3 | import com.example.common.annotation.LoginCheck; 4 | import com.example.common.annotation.MustAdmin; 5 | import com.example.common.enums.ErrorCode; 6 | import com.example.common.exception.BusinessException; 7 | import com.example.common.model.dto.InterfaceAddDto; 8 | import com.example.common.model.dto.InterfaceInvokeDto; 9 | import com.example.common.model.dto.InterfacePageDto; 10 | import com.example.common.model.dto.InterfaceUpdateDto; 11 | import com.example.common.model.entity.InterfaceInfo; 12 | import com.example.common.model.vo.InterfaceVo; 13 | import com.example.common.utils.PageBean; 14 | import com.example.common.utils.Result; 15 | import com.example.server.service.InterfaceService; 16 | import org.springframework.web.bind.annotation.DeleteMapping; 17 | import org.springframework.web.bind.annotation.GetMapping; 18 | import org.springframework.web.bind.annotation.PathVariable; 19 | import org.springframework.web.bind.annotation.PostMapping; 20 | import org.springframework.web.bind.annotation.PutMapping; 21 | import org.springframework.web.bind.annotation.RequestBody; 22 | import org.springframework.web.bind.annotation.RequestMapping; 23 | import org.springframework.web.bind.annotation.RestController; 24 | 25 | import javax.annotation.Resource; 26 | import javax.servlet.http.HttpServletRequest; 27 | import java.util.List; 28 | 29 | /** 30 | * @author by 31 | */ 32 | @RestController 33 | @RequestMapping("/interface") 34 | public class InterfaceController { 35 | 36 | @Resource 37 | private InterfaceService interfaceService; 38 | 39 | @PostMapping("/add") 40 | @MustAdmin 41 | public Result addInterface(@RequestBody InterfaceAddDto interfaceAddDto) { 42 | if (interfaceAddDto == null) { 43 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 44 | } 45 | interfaceService.addInterface(interfaceAddDto); 46 | return Result.success(); 47 | } 48 | 49 | @DeleteMapping("/delete/{id}") 50 | @MustAdmin 51 | public Result deleteInterface(@PathVariable Long id) { 52 | if (id == null || id <= 0) { 53 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 54 | } 55 | interfaceService.deleteInterface(id); 56 | return Result.success(); 57 | } 58 | 59 | @PutMapping("/update") 60 | @MustAdmin 61 | public Result updateInterface(@RequestBody InterfaceUpdateDto interfaceUpdateDto) { 62 | if (interfaceUpdateDto == null) { 63 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 64 | } 65 | interfaceService.updateInterface(interfaceUpdateDto); 66 | return Result.success(); 67 | } 68 | 69 | @GetMapping("/page") 70 | @LoginCheck 71 | public Result> listInterfacesByPage(InterfacePageDto interfacePageDto) { 72 | if (interfacePageDto == null) { 73 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 74 | } 75 | PageBean pageBean = interfaceService.listInterfacesByPage(interfacePageDto); 76 | return Result.success(pageBean); 77 | } 78 | 79 | @PutMapping("/alter/status") 80 | @MustAdmin 81 | public Result alterStatus(Long id, Integer status) { 82 | if (id == null || status == null) { 83 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 84 | } 85 | interfaceService.alterStatus(id, status); 86 | return Result.success(); 87 | } 88 | 89 | @GetMapping("/get/{id}") 90 | @LoginCheck 91 | public Result getInterfaceById(@PathVariable Long id, HttpServletRequest request) { 92 | if (id == null || id <= 0) { 93 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 94 | } 95 | InterfaceVo interfaceVo = interfaceService.getInterfaceById(id, request); 96 | return Result.success(interfaceVo); 97 | } 98 | 99 | @PostMapping("/invoke") 100 | @LoginCheck 101 | public Result invokeInterface(@RequestBody InterfaceInvokeDto interfaceInvokeDto, HttpServletRequest request) { 102 | if (interfaceInvokeDto == null || request == null) { 103 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 104 | } 105 | Object res = interfaceService.invokeInterface(interfaceInvokeDto, request); 106 | return Result.success(res); 107 | } 108 | 109 | @PostMapping("/open") 110 | @LoginCheck 111 | public Result openPermission(Long interfaceId, HttpServletRequest request) { 112 | if (interfaceId == null || interfaceId <= 0) { 113 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 114 | } 115 | interfaceService.openPermission(interfaceId, request); 116 | return Result.success(); 117 | } 118 | 119 | @GetMapping("/list/record") 120 | @LoginCheck 121 | public Result> listInvokeRecords(HttpServletRequest request) { 122 | if (request == null) { 123 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 124 | } 125 | List interfaceVos = interfaceService.listInvokeRecords(request); 126 | return Result.success(interfaceVos); 127 | } 128 | 129 | @GetMapping("/get/code") 130 | @LoginCheck 131 | public Result getCodeExample(Long interfaceId) { 132 | if (interfaceId == null || interfaceId <= 0) { 133 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 134 | } 135 | String codeExample = interfaceService.getCodeExample(interfaceId); 136 | return Result.success(codeExample); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /byapi-server/src/main/java/com/example/server/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.example.server.controller; 2 | 3 | import cn.hutool.core.util.StrUtil; 4 | import com.example.common.annotation.LoginCheck; 5 | import com.example.common.annotation.MustAdmin; 6 | import com.example.common.constant.UserConsts; 7 | import com.example.common.enums.ErrorCode; 8 | import com.example.common.exception.BusinessException; 9 | import com.example.common.model.dto.EmailDto; 10 | import com.example.common.model.dto.LoginDto; 11 | import com.example.common.model.dto.RegisterDto; 12 | import com.example.common.model.dto.UserPageDto; 13 | import com.example.common.model.dto.UserUpdateDto; 14 | import com.example.common.model.entity.User; 15 | import com.example.common.model.vo.KeyVo; 16 | import com.example.common.model.vo.UserVo; 17 | import com.example.common.utils.PageBean; 18 | import com.example.common.utils.Result; 19 | import com.example.server.service.UserService; 20 | import org.springframework.web.bind.annotation.DeleteMapping; 21 | import org.springframework.web.bind.annotation.GetMapping; 22 | import org.springframework.web.bind.annotation.PathVariable; 23 | import org.springframework.web.bind.annotation.PostMapping; 24 | import org.springframework.web.bind.annotation.PutMapping; 25 | import org.springframework.web.bind.annotation.RequestBody; 26 | import org.springframework.web.bind.annotation.RequestMapping; 27 | import org.springframework.web.bind.annotation.RestController; 28 | import org.springframework.web.multipart.MultipartFile; 29 | 30 | import javax.annotation.Resource; 31 | import javax.servlet.http.HttpServletRequest; 32 | import javax.servlet.http.HttpServletResponse; 33 | 34 | /** 35 | * @author by 36 | */ 37 | @RestController 38 | @RequestMapping("/user") 39 | public class UserController { 40 | 41 | @Resource 42 | private UserService userService; 43 | 44 | @PostMapping("/login") 45 | public Result userLogin(@RequestBody LoginDto loginDto, HttpServletRequest request) { 46 | if (loginDto == null) { 47 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 48 | } 49 | UserVo userVo = userService.userLogin(loginDto, request); 50 | return Result.success(userVo); 51 | } 52 | 53 | @PostMapping("/email/login") 54 | public Result emailLogin(@RequestBody EmailDto emailDto, HttpServletRequest request) { 55 | if (emailDto == null || request == null) { 56 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 57 | } 58 | UserVo userVo = userService.emailLogin(emailDto, request); 59 | return Result.success(userVo); 60 | } 61 | 62 | @PostMapping("/logout") 63 | @LoginCheck 64 | public Result userLogout(HttpServletRequest request) { 65 | if (request == null) { 66 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 67 | } 68 | request.getSession().setAttribute(UserConsts.USER_LOGIN_STATE, null); 69 | return Result.success(); 70 | } 71 | 72 | @GetMapping("/get/loginUser") 73 | public Result getLoginUser(HttpServletRequest request) { 74 | if (request == null) { 75 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 76 | } 77 | UserVo userVo = userService.getLoginUser(request); 78 | return Result.success(userVo); 79 | } 80 | 81 | @PostMapping("/register") 82 | public Result userRegister(@RequestBody RegisterDto registerDto) { 83 | if (registerDto == null) { 84 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 85 | } 86 | userService.userRegister(registerDto); 87 | return Result.success(); 88 | } 89 | 90 | @PostMapping("/email/register") 91 | public Result emailRegister(@RequestBody EmailDto emailDto) { 92 | if (emailDto == null) { 93 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 94 | } 95 | userService.emailRegister(emailDto); 96 | return Result.success(); 97 | } 98 | 99 | @DeleteMapping("/delete/{id}") 100 | @MustAdmin 101 | public Result deleteUser(@PathVariable Long id) { 102 | if (id == null || id <= 0) { 103 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 104 | } 105 | userService.removeById(id); 106 | return Result.success(); 107 | } 108 | 109 | @PutMapping("/update") 110 | @LoginCheck 111 | public Result updateUser(@RequestBody UserUpdateDto userUpdateDto, HttpServletRequest request) { 112 | if (userUpdateDto == null) { 113 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 114 | } 115 | userService.updateUser(userUpdateDto, request); 116 | return Result.success(); 117 | } 118 | 119 | @GetMapping("/page") 120 | @MustAdmin 121 | public Result> listUsersByPage(UserPageDto userPageDto) { 122 | if (userPageDto == null) { 123 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 124 | } 125 | PageBean pageBean = userService.listUsersByPage(userPageDto); 126 | return Result.success(pageBean); 127 | } 128 | 129 | @PutMapping("/alter/status") 130 | @MustAdmin 131 | public Result alterStatus(Long id, Integer status) { 132 | if (id == null || status == null) { 133 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 134 | } 135 | userService.alterStatus(id, status); 136 | return Result.success(); 137 | } 138 | 139 | @PostMapping("/upload/avatar") 140 | @LoginCheck 141 | public Result uploadAvatar(MultipartFile multipartFile) { 142 | if (multipartFile == null) { 143 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 144 | } 145 | String imageUrl = userService.uploadAvatar(multipartFile); 146 | return Result.success(imageUrl); 147 | } 148 | 149 | @GetMapping("/get/avatar/{fileName}") 150 | @LoginCheck 151 | public void getAvatar(@PathVariable String fileName, HttpServletResponse response) { 152 | if (StrUtil.isBlank(fileName) || response == null) { 153 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 154 | } 155 | userService.getAvatar(fileName, response); 156 | } 157 | 158 | @PostMapping("/apply/key") 159 | @LoginCheck 160 | public Result applyKey(HttpServletRequest request) { 161 | if (request == null) { 162 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 163 | } 164 | KeyVo keyVo = userService.applyKey(request); 165 | return Result.success(keyVo); 166 | } 167 | 168 | @PostMapping("/mail/send") 169 | public Result sendMail(String email, HttpServletRequest request) { 170 | if (email == null || request == null) { 171 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 172 | } 173 | userService.sendEmail(email, request); 174 | return Result.success(); 175 | } 176 | 177 | @GetMapping("/get/key") 178 | @LoginCheck 179 | public Result getKeyById(HttpServletRequest request) { 180 | if (request == null) { 181 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 182 | } 183 | KeyVo keyVo = userService.getKeyById(request); 184 | return Result.success(keyVo); 185 | } 186 | 187 | @GetMapping("/download/jar") 188 | @LoginCheck 189 | public void downloadJar(HttpServletResponse response) { 190 | if (response == null) { 191 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 192 | } 193 | userService.downloadJar(response); 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /byapi-server/src/main/java/com/example/server/controller/UserInterfaceController.java: -------------------------------------------------------------------------------- 1 | package com.example.server.controller; 2 | 3 | import com.example.common.annotation.LoginCheck; 4 | import com.example.common.annotation.MustAdmin; 5 | import com.example.common.enums.ErrorCode; 6 | import com.example.common.exception.BusinessException; 7 | import com.example.common.model.dto.UserInterfacePageDto; 8 | import com.example.common.model.dto.UserInterfaceUpdateDto; 9 | import com.example.common.model.entity.UserInterfaceInfo; 10 | import com.example.common.model.vo.InvokeCountVo; 11 | import com.example.common.utils.PageBean; 12 | import com.example.common.utils.Result; 13 | import com.example.server.service.UserInterfaceService; 14 | import org.springframework.web.bind.annotation.DeleteMapping; 15 | import org.springframework.web.bind.annotation.GetMapping; 16 | import org.springframework.web.bind.annotation.PostMapping; 17 | import org.springframework.web.bind.annotation.PutMapping; 18 | import org.springframework.web.bind.annotation.RequestBody; 19 | import org.springframework.web.bind.annotation.RequestMapping; 20 | import org.springframework.web.bind.annotation.RestController; 21 | 22 | import javax.annotation.Resource; 23 | import javax.servlet.http.HttpServletRequest; 24 | import java.util.List; 25 | 26 | /** 27 | * @author by 28 | */ 29 | @RestController 30 | @RequestMapping("/userInterface") 31 | public class UserInterfaceController { 32 | 33 | @Resource 34 | private UserInterfaceService userInterfaceService; 35 | 36 | @DeleteMapping("/delete") 37 | @MustAdmin 38 | public Result delUserInterface(Long id) { 39 | if (id == null || id <= 0) { 40 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 41 | } 42 | userInterfaceService.removeById(id); 43 | return Result.success(); 44 | } 45 | 46 | @PutMapping("/update") 47 | @MustAdmin 48 | public Result updateUserInterface(@RequestBody UserInterfaceUpdateDto userInterfaceUpdateDto) { 49 | if (userInterfaceUpdateDto == null) { 50 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 51 | } 52 | userInterfaceService.updateUserInterface(userInterfaceUpdateDto); 53 | return Result.success(); 54 | } 55 | 56 | @GetMapping("/page") 57 | @MustAdmin 58 | public Result> pageUserInterfaces(UserInterfacePageDto userInterfacePageDto) { 59 | if (userInterfacePageDto == null) { 60 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 61 | } 62 | PageBean pageBean = userInterfaceService.pageUserInterfaces(userInterfacePageDto); 63 | return Result.success(pageBean); 64 | } 65 | 66 | @PostMapping("/add/count") 67 | @LoginCheck 68 | public Result addInvokeCount(Long interfaceId, HttpServletRequest request) { 69 | if (interfaceId == null || interfaceId <= 0) { 70 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 71 | } 72 | userInterfaceService.addInvokeCount(interfaceId, request); 73 | return Result.success(); 74 | } 75 | 76 | @GetMapping("/invoke/count") 77 | @LoginCheck 78 | public Result> getInvokeCountList() { 79 | List invokeCountVoList = userInterfaceService.getInvokeCountList(); 80 | return Result.success(invokeCountVoList); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /byapi-server/src/main/java/com/example/server/mapper/InterfaceMapper.java: -------------------------------------------------------------------------------- 1 | package com.example.server.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.example.common.model.entity.InterfaceInfo; 5 | import org.apache.ibatis.annotations.Mapper; 6 | 7 | /** 8 | * @author by 9 | */ 10 | @Mapper 11 | public interface InterfaceMapper extends BaseMapper { 12 | } 13 | -------------------------------------------------------------------------------- /byapi-server/src/main/java/com/example/server/mapper/UserInterfaceMapper.java: -------------------------------------------------------------------------------- 1 | package com.example.server.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.example.common.model.entity.UserInterfaceInfo; 5 | import org.apache.ibatis.annotations.Mapper; 6 | 7 | /** 8 | * @author by 9 | */ 10 | @Mapper 11 | public interface UserInterfaceMapper extends BaseMapper { 12 | 13 | } 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /byapi-server/src/main/java/com/example/server/mapper/UserMapper.java: -------------------------------------------------------------------------------- 1 | package com.example.server.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.baomidou.mybatisplus.core.metadata.IPage; 5 | import com.example.common.model.dto.UserPageDto; 6 | import com.example.common.model.entity.User; 7 | import org.apache.ibatis.annotations.Mapper; 8 | import org.apache.ibatis.annotations.Param; 9 | 10 | /** 11 | * @author by 12 | */ 13 | @Mapper 14 | public interface UserMapper extends BaseMapper { 15 | 16 | /** 17 | * 分页查询用户信息 18 | * 19 | * @param pageCondition 分页条件 20 | * @param userPageDto 查询参数 21 | * @return 用户列表 22 | */ 23 | IPage listUsersByPage(@Param("pageCondition") IPage pageCondition, @Param("dto") UserPageDto userPageDto); 24 | } 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /byapi-server/src/main/java/com/example/server/service/InterfaceService.java: -------------------------------------------------------------------------------- 1 | package com.example.server.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.example.common.model.dto.InterfaceAddDto; 5 | import com.example.common.model.dto.InterfaceInvokeDto; 6 | import com.example.common.model.dto.InterfacePageDto; 7 | import com.example.common.model.dto.InterfaceUpdateDto; 8 | import com.example.common.model.entity.InterfaceInfo; 9 | import com.example.common.model.vo.InterfaceVo; 10 | import com.example.common.utils.PageBean; 11 | 12 | import javax.servlet.http.HttpServletRequest; 13 | import java.util.List; 14 | 15 | /** 16 | * @author by 17 | */ 18 | public interface InterfaceService extends IService { 19 | 20 | /** 21 | * 添加接口 22 | * 23 | * @param interfaceAddDto 添加接口请求体 24 | */ 25 | void addInterface(InterfaceAddDto interfaceAddDto); 26 | 27 | /** 28 | * 根据ID删除接口 29 | * 30 | * @param id 接口ID 31 | */ 32 | void deleteInterface(Long id); 33 | 34 | /** 35 | * 更新接口 36 | * 37 | * @param interfaceUpdateDto 更新接口请求体 38 | */ 39 | void updateInterface(InterfaceUpdateDto interfaceUpdateDto); 40 | 41 | /** 42 | * 分页查询接口 43 | * 44 | * @param interfacePageDto 接口分页请求体 45 | * @return 接口分页响应体 46 | */ 47 | PageBean listInterfacesByPage(InterfacePageDto interfacePageDto); 48 | 49 | /** 50 | * 更改接口状态 51 | * 52 | * @param id 接口ID 53 | * @param status 状态 54 | */ 55 | void alterStatus(Long id, Integer status); 56 | 57 | /** 58 | * 根据ID调用接口 59 | * 60 | * @param interfaceInvokeDto 接口调用请求体 61 | * @param request 请求对象 62 | * @return 调用结果 63 | */ 64 | Object invokeInterface(InterfaceInvokeDto interfaceInvokeDto, HttpServletRequest request); 65 | 66 | /** 67 | * 开通接口权限 68 | * 69 | * @param interfaceId 接口ID 70 | * @param request 请求对象 71 | */ 72 | void openPermission(Long interfaceId, HttpServletRequest request); 73 | 74 | /** 75 | * 根据ID获取接口信息 76 | * 77 | * @param id 接口ID 78 | * @param request 请求对象 79 | * @return 接口信息 80 | */ 81 | InterfaceVo getInterfaceById(Long id, HttpServletRequest request); 82 | 83 | /** 84 | * 获取接口调用记录 85 | * 86 | * @param request 请求对象 87 | * @return 记录 88 | */ 89 | List listInvokeRecords(HttpServletRequest request); 90 | 91 | /** 92 | * 根据接口ID获取代码示例 93 | * 94 | * @param interfaceId 接口ID 95 | * @return 代码示例 96 | */ 97 | String getCodeExample(Long interfaceId); 98 | } 99 | -------------------------------------------------------------------------------- /byapi-server/src/main/java/com/example/server/service/UserInterfaceService.java: -------------------------------------------------------------------------------- 1 | package com.example.server.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.example.common.model.dto.UserInterfacePageDto; 5 | import com.example.common.model.dto.UserInterfaceUpdateDto; 6 | import com.example.common.model.entity.UserInterfaceInfo; 7 | import com.example.common.model.vo.InvokeCountVo; 8 | import com.example.common.utils.PageBean; 9 | 10 | import javax.servlet.http.HttpServletRequest; 11 | import java.util.List; 12 | 13 | /** 14 | * @author by 15 | */ 16 | public interface UserInterfaceService extends IService { 17 | 18 | /** 19 | * 统计接口调用次数 20 | * 21 | * @param interfaceId 接口ID 22 | * @param userId 用户ID 23 | */ 24 | void invokeCount(long interfaceId, long userId); 25 | 26 | /** 27 | * 添加用户接口关联信息 28 | * 29 | * @param interfaceId 接口ID 30 | * @param userId 用户ID 31 | */ 32 | void addUserInterface(Long interfaceId, Long userId); 33 | 34 | /** 35 | * 更新用户接口关联信息 36 | * 37 | * @param userInterfaceUpdateDto 用户接口信息请体 38 | */ 39 | void updateUserInterface(UserInterfaceUpdateDto userInterfaceUpdateDto); 40 | 41 | /** 42 | * 条件分页查询 43 | * 44 | * @param userInterfacePageDto 查询请求体 45 | * @return 查询数据 46 | */ 47 | PageBean pageUserInterfaces(UserInterfacePageDto userInterfacePageDto); 48 | 49 | /** 50 | * 增加接口调用次数 51 | * 52 | * @param interfaceId 接口ID 53 | * @param request 请求对象 54 | */ 55 | void addInvokeCount(Long interfaceId, HttpServletRequest request); 56 | 57 | /** 58 | * 获取接口调用次数列表 59 | * 60 | * @return 列表 61 | */ 62 | List getInvokeCountList(); 63 | } 64 | -------------------------------------------------------------------------------- /byapi-server/src/main/java/com/example/server/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.example.server.service; 2 | 3 | import com.example.common.model.dto.EmailDto; 4 | import com.example.common.model.dto.LoginDto; 5 | import com.example.common.model.dto.RegisterDto; 6 | import com.example.common.model.dto.UserPageDto; 7 | import com.example.common.model.dto.UserUpdateDto; 8 | import com.example.common.model.entity.User; 9 | import com.baomidou.mybatisplus.extension.service.IService; 10 | import com.example.common.model.vo.KeyVo; 11 | import com.example.common.model.vo.UserVo; 12 | import com.example.common.utils.PageBean; 13 | import org.springframework.web.multipart.MultipartFile; 14 | 15 | import javax.servlet.http.HttpServletRequest; 16 | import javax.servlet.http.HttpServletResponse; 17 | import java.io.FileNotFoundException; 18 | 19 | /** 20 | * @author by 21 | */ 22 | public interface UserService extends IService { 23 | 24 | /** 25 | * 用户登录 26 | * 27 | * @param loginDto 登录请求体 28 | * @param request 请求对象 29 | * @return 脱敏后的用户信息 30 | */ 31 | UserVo userLogin(LoginDto loginDto, HttpServletRequest request); 32 | 33 | /** 34 | * 用户注册 35 | * 36 | * @param registerDto 注册请求体 37 | */ 38 | void userRegister(RegisterDto registerDto); 39 | 40 | /** 41 | * 获取当前登录用户信息 42 | * 43 | * @param request 请求对象 44 | * @return 返回用户信息 45 | */ 46 | UserVo getLoginUser(HttpServletRequest request); 47 | 48 | /** 49 | * 更新用户信息 50 | * 51 | * @param userUpdateDto 用户更新信息 52 | * @param request 请求对象 53 | */ 54 | void updateUser(UserUpdateDto userUpdateDto, HttpServletRequest request); 55 | 56 | /** 57 | * 分页条件查询 58 | * 59 | * @param userPageDto 查询请求体 60 | * @return 用户数据 61 | */ 62 | PageBean listUsersByPage(UserPageDto userPageDto); 63 | 64 | /** 65 | * 修改用户状态 66 | * 67 | * @param id 用户ID 68 | * @param status 用户状态 69 | */ 70 | void alterStatus(Long id, Integer status); 71 | 72 | /** 73 | * 上传头像 74 | * 75 | * @param multipartFile 文件 76 | * @return 头像地址 77 | */ 78 | String uploadAvatar(MultipartFile multipartFile); 79 | 80 | /** 81 | * 获取头像 82 | * 83 | * @param fileName 文件名 84 | * @param response 响应对象 85 | */ 86 | void getAvatar(String fileName, HttpServletResponse response); 87 | 88 | /** 89 | * 给指定用户分发密钥 90 | * 91 | * @param request 请求对象 92 | * @return 密钥对 93 | */ 94 | KeyVo applyKey(HttpServletRequest request); 95 | 96 | /** 97 | * 发送邮件 98 | * 99 | * @param mail 指定邮箱 100 | * @param request 请求对象 101 | */ 102 | void sendEmail(String mail, HttpServletRequest request); 103 | 104 | /** 105 | * 邮箱登录 106 | * 107 | * @param emailDto 邮箱登录请求体 108 | * @param request 请求对象 109 | * @return 登录用户信息 110 | */ 111 | UserVo emailLogin(EmailDto emailDto, HttpServletRequest request); 112 | 113 | /** 114 | * 邮箱注册 115 | * 116 | * @param emailDto 邮箱注册请求体 117 | */ 118 | void emailRegister(EmailDto emailDto); 119 | 120 | /** 121 | * 根据ID获取用户的密钥 122 | * 123 | * @param request 请求对象 124 | * @return 密钥 125 | */ 126 | KeyVo getKeyById(HttpServletRequest request); 127 | 128 | /** 129 | * 下载SDK的jar包 130 | * 131 | * @param response 响应对象 132 | */ 133 | void downloadJar(HttpServletResponse response); 134 | } 135 | -------------------------------------------------------------------------------- /byapi-server/src/main/java/com/example/server/service/dubbo/DubboInterfaceServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.example.server.service.dubbo; 2 | 3 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 4 | import com.example.common.enums.ErrorCode; 5 | import com.example.common.exception.BusinessException; 6 | import com.example.common.model.entity.InterfaceInfo; 7 | import com.example.common.service.DubboInterfaceService; 8 | import com.example.server.service.InterfaceService; 9 | import org.apache.commons.lang3.StringUtils; 10 | import org.apache.dubbo.config.annotation.DubboService; 11 | 12 | import javax.annotation.Resource; 13 | 14 | /** 15 | * @author by 16 | */ 17 | @DubboService 18 | public class DubboInterfaceServiceImpl implements DubboInterfaceService { 19 | 20 | @Resource 21 | private InterfaceService interfaceService; 22 | 23 | /** 24 | * 根据url和method获取接口信息 25 | * 26 | * @param url 接口地址 27 | * @param method 接口方法 28 | * @return 接口信息 29 | */ 30 | @Override 31 | public InterfaceInfo getInterfaceInfo(String url, String method) { 32 | if (StringUtils.isAnyBlank(url, method)) { 33 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 34 | } 35 | LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); 36 | wrapper.eq(InterfaceInfo::getUrl, url); 37 | wrapper.eq(InterfaceInfo::getMethod, method); 38 | return interfaceService.getOne(wrapper); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /byapi-server/src/main/java/com/example/server/service/dubbo/DubboUserInterfaceServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.example.server.service.dubbo; 2 | 3 | import com.example.common.service.DubboUserInterfaceService; 4 | import com.example.server.service.UserInterfaceService; 5 | import org.apache.dubbo.config.annotation.DubboService; 6 | 7 | import javax.annotation.Resource; 8 | 9 | /** 10 | * 对外暴露的Dubbo服务 11 | * 12 | * @author by 13 | */ 14 | @DubboService 15 | public class DubboUserInterfaceServiceImpl implements DubboUserInterfaceService { 16 | 17 | @Resource 18 | private UserInterfaceService userInterfaceService; 19 | 20 | /** 21 | * 统计接口调用次数 22 | * 23 | * @param interfaceId 接口ID 24 | * @param userId 用户ID 25 | */ 26 | @Override 27 | public void invokeCount(long interfaceId, long userId) { 28 | userInterfaceService.invokeCount(interfaceId, userId); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /byapi-server/src/main/java/com/example/server/service/dubbo/DubboUserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.example.server.service.dubbo; 2 | 3 | import cn.hutool.core.util.StrUtil; 4 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 5 | import com.example.common.enums.ErrorCode; 6 | import com.example.common.exception.BusinessException; 7 | import com.example.common.model.entity.User; 8 | import com.example.common.service.DubboUserService; 9 | import com.example.server.service.UserService; 10 | import org.apache.dubbo.config.annotation.DubboService; 11 | 12 | import javax.annotation.Resource; 13 | 14 | /** 15 | * @author by 16 | */ 17 | @DubboService 18 | public class DubboUserServiceImpl implements DubboUserService { 19 | 20 | @Resource 21 | private UserService userService; 22 | 23 | @Override 24 | public User getInvokeUser(String accessKey) { 25 | if (StrUtil.isBlank(accessKey)) { 26 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 27 | } 28 | LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); 29 | wrapper.eq(User::getAccessKey, accessKey); 30 | return userService.getOne(wrapper); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /byapi-server/src/main/java/com/example/server/service/impl/InterfaceServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.example.server.service.impl; 2 | 3 | import cn.hutool.core.bean.BeanUtil; 4 | import cn.hutool.core.util.StrUtil; 5 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 6 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 7 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 8 | import com.example.client.ByApiClient; 9 | import com.example.common.constant.CommonConsts; 10 | import com.example.common.constant.InterfaceConsts; 11 | import com.example.common.enums.ErrorCode; 12 | import com.example.common.exception.BusinessException; 13 | import com.example.common.model.dto.InterfaceAddDto; 14 | import com.example.common.model.dto.InterfaceInvokeDto; 15 | import com.example.common.model.dto.InterfacePageDto; 16 | import com.example.common.model.dto.InterfaceUpdateDto; 17 | import com.example.common.model.entity.InterfaceInfo; 18 | import com.example.common.model.entity.User; 19 | import com.example.common.model.entity.UserInterfaceInfo; 20 | import com.example.common.model.vo.InterfaceVo; 21 | import com.example.common.model.vo.UserVo; 22 | import com.example.common.utils.PageBean; 23 | import com.example.server.mapper.InterfaceMapper; 24 | import com.example.server.service.InterfaceService; 25 | import com.example.server.service.UserInterfaceService; 26 | import com.example.server.service.UserService; 27 | import lombok.extern.slf4j.Slf4j; 28 | import org.apache.commons.lang3.StringUtils; 29 | import org.springframework.data.redis.core.RedisTemplate; 30 | import org.springframework.data.redis.core.ValueOperations; 31 | import org.springframework.stereotype.Service; 32 | import org.springframework.util.CollectionUtils; 33 | 34 | import javax.annotation.Resource; 35 | import javax.servlet.http.HttpServletRequest; 36 | import java.lang.reflect.Method; 37 | import java.util.ArrayList; 38 | import java.util.List; 39 | import java.util.concurrent.TimeUnit; 40 | import java.util.stream.Collectors; 41 | 42 | /** 43 | * @author by 44 | */ 45 | @Service 46 | @Slf4j 47 | public class InterfaceServiceImpl extends ServiceImpl implements InterfaceService { 48 | 49 | @Resource 50 | private UserService userService; 51 | @Resource 52 | private InterfaceService interfaceService; 53 | @Resource 54 | private UserInterfaceService userInterfaceService; 55 | @Resource 56 | private RedisTemplate redisTemplate; 57 | 58 | @Override 59 | public void addInterface(InterfaceAddDto interfaceAddDto) { 60 | //判断部分参数是否合法 61 | String name = interfaceAddDto.getName(); 62 | String url = interfaceAddDto.getUrl(); 63 | String method = interfaceAddDto.getMethod(); 64 | Integer status = interfaceAddDto.getStatus(); 65 | if (StringUtils.isAnyBlank(name, url, method)) { 66 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 67 | } 68 | if (status == null) { 69 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 70 | } 71 | //添加接口 72 | InterfaceInfo interfaceInfo = new InterfaceInfo(); 73 | BeanUtil.copyProperties(interfaceAddDto, interfaceInfo); 74 | this.save(interfaceInfo); 75 | } 76 | 77 | @Override 78 | public void deleteInterface(Long id) { 79 | //判断接口是否存在 80 | InterfaceInfo interfaceInfo = this.getById(id); 81 | if (interfaceInfo == null) { 82 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 83 | } 84 | //判断接口是否处于上线状态 85 | Integer status = interfaceInfo.getStatus(); 86 | if (status == 1) { 87 | throw new BusinessException(ErrorCode.PARAMS_ERROR, InterfaceConsts.INTERFACE_ONLINE_ERROR); 88 | } 89 | //删除 90 | this.removeById(id); 91 | } 92 | 93 | @Override 94 | public void updateInterface(InterfaceUpdateDto interfaceUpdateDto) { 95 | //判断部分参数是否符合要求 96 | Long id = interfaceUpdateDto.getId(); 97 | String name = interfaceUpdateDto.getName(); 98 | String url = interfaceUpdateDto.getUrl(); 99 | String method = interfaceUpdateDto.getMethod(); 100 | if (id == null || id <= 0) { 101 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 102 | } 103 | if (StringUtils.isAnyBlank(name, url, method)) { 104 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 105 | } 106 | //更新接口 107 | InterfaceInfo interfaceInfo = new InterfaceInfo(); 108 | BeanUtil.copyProperties(interfaceUpdateDto, interfaceInfo); 109 | this.updateById(interfaceInfo); 110 | } 111 | 112 | @Override 113 | public PageBean listInterfacesByPage(InterfacePageDto interfacePageDto) { 114 | Long id = interfacePageDto.getId(); 115 | String name = interfacePageDto.getName(); 116 | String url = interfacePageDto.getUrl(); 117 | String method = interfacePageDto.getMethod(); 118 | Integer status = interfacePageDto.getStatus(); 119 | Integer current = interfacePageDto.getCurrent(); 120 | Integer pageSize = interfacePageDto.getPageSize(); 121 | //校验分页参数 122 | if (current == null || current <= 0) { 123 | throw new BusinessException(ErrorCode.PARAMS_ERROR, CommonConsts.PAGE_PARAMS_ERROR); 124 | } 125 | if (pageSize == null || pageSize < 0) { 126 | throw new BusinessException(ErrorCode.PARAMS_ERROR, CommonConsts.PAGE_PARAMS_ERROR); 127 | } 128 | //添加分页条件 129 | Page page = new Page<>(current, pageSize); 130 | //添加查询条件 131 | LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); 132 | wrapper.eq(id != null, InterfaceInfo::getId, id); 133 | wrapper.like(StrUtil.isNotBlank(name), InterfaceInfo::getName, name); 134 | wrapper.like(StrUtil.isNotBlank(url), InterfaceInfo::getUrl, url); 135 | wrapper.eq(StrUtil.isNotBlank(method), InterfaceInfo::getMethod, method); 136 | wrapper.eq(status != null, InterfaceInfo::getStatus, status); 137 | //查询 138 | this.page(page, wrapper); 139 | //获取记录 140 | long total = page.getTotal(); 141 | List records = page.getRecords(); 142 | //返回 143 | return PageBean.of(total, records); 144 | } 145 | 146 | @Override 147 | public void alterStatus(Long id, Integer status) { 148 | if (id <= 0 || status < 0 || status > 1) { 149 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 150 | } 151 | //查询接口 152 | InterfaceInfo interfaceInfo = this.getById(id); 153 | if (interfaceInfo == null) { 154 | throw new BusinessException(ErrorCode.NOT_FOUND_ERROR); 155 | } 156 | //判断状态是否一致 157 | if (status.equals(interfaceInfo.getStatus())) { 158 | return; 159 | } 160 | interfaceInfo.setStatus(status); 161 | this.updateById(interfaceInfo); 162 | } 163 | 164 | @Override 165 | public Object invokeInterface(InterfaceInvokeDto interfaceInvokeDto, HttpServletRequest request) { 166 | Long id = interfaceInvokeDto.getId(); 167 | String userRequestParams = interfaceInvokeDto.getUserRequestParams(); 168 | //判断参数是否为空 169 | if (id == null || id <= 0) { 170 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 171 | } 172 | //判断接口是否存在 173 | InterfaceInfo interfaceInfo = this.getById(id); 174 | if (interfaceInfo == null) { 175 | throw new BusinessException(ErrorCode.NOT_FOUND_ERROR); 176 | } 177 | //判断接口是否处于关闭状态 178 | if (interfaceInfo.getStatus() == 0) { 179 | throw new BusinessException(ErrorCode.PARAMS_ERROR, InterfaceConsts.INTERFACE_CLOSE); 180 | } 181 | //获取当前登录用户ID 182 | UserVo loginUser = userService.getLoginUser(request); 183 | Long userId = loginUser.getId(); 184 | //判断用户是否有权限 185 | User user = userService.getById(userId); 186 | String accessKey = user.getAccessKey(); 187 | String secretKey = user.getSecretKey(); 188 | //如果没有签名和密钥,则抛出异常 189 | if (StringUtils.isAnyBlank(accessKey, secretKey)) { 190 | throw new BusinessException(ErrorCode.NO_AUTH_ERROR); 191 | } 192 | //判断用户是否还有调用次数 193 | LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); 194 | wrapper.eq(UserInterfaceInfo::getInterfaceId, id); 195 | wrapper.eq(UserInterfaceInfo::getUserId, userId); 196 | UserInterfaceInfo userInterfaceInfo = userInterfaceService.getOne(wrapper); 197 | if (userInterfaceInfo == null) { 198 | throw new BusinessException(ErrorCode.NO_AUTH_ERROR); 199 | } 200 | if (userInterfaceInfo.getLeftNum() == 0) { 201 | throw new BusinessException(ErrorCode.PARAMS_ERROR, InterfaceConsts.INVOKE_COUNT_ERROR); 202 | } 203 | //创建一个SDK客户端 204 | ByApiClient byApiClient = new ByApiClient(accessKey, secretKey); 205 | //利用反射根据接口名称动态调用接口 206 | Class byApiClientClass = byApiClient.getClass(); 207 | //根据接口名称获取方法 208 | Method method; 209 | try { 210 | //判断用户是否传递了参数 211 | if (StrUtil.isNotBlank(userRequestParams)) { 212 | method = byApiClientClass.getMethod(interfaceInfo.getName(), String.class); 213 | //调用方法 214 | return method.invoke(byApiClient, userRequestParams); 215 | } 216 | method = byApiClientClass.getMethod(interfaceInfo.getName()); 217 | //调用方法 218 | return method.invoke(byApiClient); 219 | } catch (Exception e) { 220 | throw new BusinessException(ErrorCode.PARAMS_ERROR, InterfaceConsts.NOT_EXIST_ERROR); 221 | } 222 | } 223 | 224 | @Override 225 | public void openPermission(Long interfaceId, HttpServletRequest request) { 226 | //获取用户ID 227 | UserVo userVo = userService.getLoginUser(request); 228 | Long userId = userVo.getId(); 229 | //为当前用户分配密钥 230 | userService.applyKey(request); 231 | //添加用户接口关系记录 232 | userInterfaceService.addUserInterface(interfaceId, userId); 233 | } 234 | 235 | @Override 236 | public InterfaceVo getInterfaceById(Long id, HttpServletRequest request) { 237 | //获取当前登录用户ID 238 | UserVo userVo = userService.getLoginUser(request); 239 | Long userId = userVo.getId(); 240 | //判断缓存是否存在 241 | ValueOperations valueOperations = redisTemplate.opsForValue(); 242 | String key = String.format(CommonConsts.GET_INTERFACE_BY_ID_KEY, userId, id); 243 | InterfaceVo interfaceVo = (InterfaceVo) valueOperations.get(key); 244 | if (interfaceVo != null) { 245 | return interfaceVo; 246 | } 247 | //判断接口是否存在 248 | LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); 249 | wrapper.eq(InterfaceInfo::getId, id); 250 | InterfaceInfo interfaceInfo = this.getOne(wrapper); 251 | if (interfaceInfo == null) { 252 | throw new BusinessException(ErrorCode.NOT_FOUND_ERROR); 253 | } 254 | //根据用户ID和接口ID查询当前用户调用次数 255 | LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); 256 | queryWrapper.eq(UserInterfaceInfo::getUserId, userId); 257 | queryWrapper.eq(UserInterfaceInfo::getInterfaceId, id); 258 | UserInterfaceInfo userInterfaceInfo = userInterfaceService.getOne(queryWrapper); 259 | //封装数据 260 | interfaceVo = new InterfaceVo(); 261 | BeanUtil.copyProperties(interfaceInfo, interfaceVo); 262 | if (userInterfaceInfo != null) { 263 | interfaceVo.setLeftNum(userInterfaceInfo.getLeftNum()); 264 | interfaceVo.setTotalNum(userInterfaceInfo.getTotalNum()); 265 | } 266 | //设置缓存 267 | try { 268 | //设置缓存时间30分钟 269 | valueOperations.set(key, interfaceVo, 30, TimeUnit.MINUTES); 270 | } catch (Exception e) { 271 | log.error("redis set key error", e); 272 | throw new BusinessException(ErrorCode.PARAMS_ERROR, CommonConsts.CACHE_SET_ERROR); 273 | } 274 | return interfaceVo; 275 | } 276 | 277 | @Override 278 | public List listInvokeRecords(HttpServletRequest request) { 279 | //获取用户ID 280 | UserVo userVo = userService.getLoginUser(request); 281 | Long userId = userVo.getId(); 282 | //判断缓存是否为空 283 | ValueOperations valueOperations = redisTemplate.opsForValue(); 284 | String key = String.format(CommonConsts.LIST_INVOKE_RECORDS_KEY, userId); 285 | List interfaceVoList = (List) valueOperations.get(key); 286 | if (!CollectionUtils.isEmpty(interfaceVoList)) { 287 | return interfaceVoList; 288 | } 289 | //根据用户ID去查询用户接口关联表 290 | LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); 291 | wrapper.eq(UserInterfaceInfo::getUserId, userId); 292 | List userInterfaceInfoList = userInterfaceService.list(wrapper); 293 | interfaceVoList = new ArrayList<>(); 294 | //如果为空直接返回 295 | if (CollectionUtils.isEmpty(userInterfaceInfoList)) { 296 | return interfaceVoList; 297 | } 298 | //封装数据 299 | interfaceVoList = userInterfaceInfoList.stream().map(userInterfaceInfo -> { 300 | InterfaceInfo interfaceInfo = interfaceService.getById(userInterfaceInfo.getInterfaceId()); 301 | InterfaceVo interfaceVo = new InterfaceVo(); 302 | BeanUtil.copyProperties(interfaceInfo, interfaceVo); 303 | interfaceVo.setTotalNum(userInterfaceInfo.getTotalNum()); 304 | interfaceVo.setLeftNum(userInterfaceInfo.getLeftNum()); 305 | return interfaceVo; 306 | }).collect(Collectors.toList()); 307 | //设置缓存 308 | try { 309 | valueOperations.set(key, interfaceVoList, 30, TimeUnit.MINUTES); 310 | } catch (Exception e) { 311 | log.error("redis set key error", e); 312 | throw new BusinessException(ErrorCode.PARAMS_ERROR, CommonConsts.CACHE_SET_ERROR); 313 | } 314 | return interfaceVoList; 315 | } 316 | 317 | @Override 318 | public String getCodeExample(Long interfaceId) { 319 | InterfaceInfo interfaceInfo = this.getById(interfaceId); 320 | if (interfaceInfo == null) { 321 | throw new BusinessException(ErrorCode.NOT_FOUND_ERROR); 322 | } 323 | return interfaceInfo.getCodeExample(); 324 | } 325 | } 326 | -------------------------------------------------------------------------------- /byapi-server/src/main/java/com/example/server/service/impl/UserInterfaceServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.example.server.service.impl; 2 | 3 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 4 | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; 5 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 6 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 7 | import com.example.common.constant.CommonConsts; 8 | import com.example.common.enums.ErrorCode; 9 | import com.example.common.exception.BusinessException; 10 | import com.example.common.model.dto.UserInterfacePageDto; 11 | import com.example.common.model.dto.UserInterfaceUpdateDto; 12 | import com.example.common.model.entity.InterfaceInfo; 13 | import com.example.common.model.entity.UserInterfaceInfo; 14 | import com.example.common.model.vo.InvokeCountVo; 15 | import com.example.common.model.vo.UserVo; 16 | import com.example.common.utils.PageBean; 17 | import com.example.server.mapper.UserInterfaceMapper; 18 | import com.example.server.service.InterfaceService; 19 | import com.example.server.service.UserInterfaceService; 20 | import com.example.server.service.UserService; 21 | import org.springframework.data.redis.core.RedisTemplate; 22 | import org.springframework.stereotype.Service; 23 | import org.springframework.util.CollectionUtils; 24 | 25 | import javax.annotation.Resource; 26 | import javax.servlet.http.HttpServletRequest; 27 | import java.util.ArrayList; 28 | import java.util.List; 29 | import java.util.Map; 30 | import java.util.stream.Collectors; 31 | 32 | /** 33 | * @author by 34 | */ 35 | @Service 36 | public class UserInterfaceServiceImpl extends ServiceImpl implements UserInterfaceService { 37 | 38 | @Resource 39 | private UserService userService; 40 | @Resource 41 | private InterfaceService interfaceService; 42 | @Resource 43 | private RedisTemplate redisTemplate; 44 | 45 | @Override 46 | public void invokeCount(long interfaceId, long userId) { 47 | if (interfaceId <= 0 || userId <= 0) { 48 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 49 | } 50 | LambdaUpdateWrapper wrapper = new LambdaUpdateWrapper<>(); 51 | wrapper.eq(UserInterfaceInfo::getInterfaceId, interfaceId); 52 | wrapper.eq(UserInterfaceInfo::getUserId, userId); 53 | wrapper.setSql("total_num=total_num + 1, left_num=left_num - 1"); 54 | this.update(wrapper); 55 | //删除缓存 56 | String key = String.format(CommonConsts.GET_INTERFACE_BY_ID_KEY, userId, interfaceId); 57 | String listKey = String.format(CommonConsts.LIST_INVOKE_RECORDS_KEY, userId); 58 | redisTemplate.delete(key); 59 | redisTemplate.delete(listKey); 60 | } 61 | 62 | @Override 63 | public void addUserInterface(Long interfaceId, Long userId) { 64 | //查询记录是否存在 65 | LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); 66 | wrapper.eq(UserInterfaceInfo::getUserId, userId); 67 | wrapper.eq(UserInterfaceInfo::getInterfaceId, interfaceId); 68 | UserInterfaceInfo userInterfaceInfo = this.getOne(wrapper); 69 | if (userInterfaceInfo != null) { 70 | throw new BusinessException(ErrorCode.PARAMS_ERROR, CommonConsts.EXIST_ERROR); 71 | } 72 | //插入记录 73 | userInterfaceInfo = new UserInterfaceInfo(); 74 | userInterfaceInfo.setUserId(userId); 75 | userInterfaceInfo.setInterfaceId(interfaceId); 76 | userInterfaceInfo.setTotalNum(0); 77 | userInterfaceInfo.setLeftNum(0); 78 | this.save(userInterfaceInfo); 79 | } 80 | 81 | @Override 82 | public void updateUserInterface(UserInterfaceUpdateDto userInterfaceUpdateDto) { 83 | Long id = userInterfaceUpdateDto.getId(); 84 | Integer totalNum = userInterfaceUpdateDto.getTotalNum(); 85 | Integer leftNum = userInterfaceUpdateDto.getLeftNum(); 86 | //校验部分参数 87 | if (id == null || id <= 0) { 88 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 89 | } 90 | if (totalNum == null || totalNum < 0) { 91 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 92 | } 93 | if (leftNum == null || leftNum < 0) { 94 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 95 | } 96 | //查询记录 97 | LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); 98 | wrapper.eq(UserInterfaceInfo::getId, id); 99 | UserInterfaceInfo userInterfaceInfo = this.getOne(wrapper); 100 | if (userInterfaceInfo == null) { 101 | throw new BusinessException(ErrorCode.NOT_FOUND_ERROR); 102 | } 103 | //更新记录 104 | userInterfaceInfo.setTotalNum(totalNum); 105 | userInterfaceInfo.setLeftNum(leftNum); 106 | this.updateById(userInterfaceInfo); 107 | } 108 | 109 | @Override 110 | public PageBean pageUserInterfaces(UserInterfacePageDto userInterfacePageDto) { 111 | Long id = userInterfacePageDto.getId(); 112 | Long userId = userInterfacePageDto.getUserId(); 113 | Long interfaceInfoId = userInterfacePageDto.getInterfaceInfoId(); 114 | Integer current = userInterfacePageDto.getCurrent(); 115 | Integer pageSize = userInterfacePageDto.getPageSize(); 116 | if (current == null || current <= 0) { 117 | throw new BusinessException(ErrorCode.PARAMS_ERROR, CommonConsts.PAGE_PARAMS_ERROR); 118 | } 119 | if (pageSize == null || pageSize < 0) { 120 | throw new BusinessException(ErrorCode.PARAMS_ERROR, CommonConsts.PAGE_PARAMS_ERROR); 121 | } 122 | //开启分页 123 | Page page = new Page<>(current, pageSize); 124 | //添加查询条件 125 | LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); 126 | wrapper.eq(id != null, UserInterfaceInfo::getId, id); 127 | wrapper.eq(userId != null, UserInterfaceInfo::getUserId, userId); 128 | wrapper.eq(interfaceInfoId != null, UserInterfaceInfo::getInterfaceId, interfaceInfoId); 129 | this.page(page, wrapper); 130 | //返回 131 | return PageBean.of(page.getTotal(), page.getRecords()); 132 | } 133 | 134 | @Override 135 | public void addInvokeCount(Long interfaceId, HttpServletRequest request) { 136 | //获取登录用户ID 137 | UserVo userVo = userService.getLoginUser(request); 138 | Long userId = userVo.getId(); 139 | //根据接口ID和用户ID查询接口调用信息 140 | LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); 141 | wrapper.eq(UserInterfaceInfo::getInterfaceId, interfaceId); 142 | wrapper.eq(UserInterfaceInfo::getUserId, userId); 143 | UserInterfaceInfo userInterfaceInfo = this.getOne(wrapper); 144 | if (userInterfaceInfo == null) { 145 | throw new BusinessException(ErrorCode.NOT_FOUND_ERROR); 146 | } 147 | //增加调用次数 148 | userInterfaceInfo.setLeftNum(10); 149 | this.updateById(userInterfaceInfo); 150 | } 151 | 152 | @Override 153 | public List getInvokeCountList() { 154 | List userInterfaceInfoList = this.list(); 155 | List invokeCountVoList = new ArrayList<>(); 156 | //如果为空直接返回 157 | if (CollectionUtils.isEmpty(userInterfaceInfoList)) { 158 | return invokeCountVoList; 159 | } 160 | //根据接口ID分组 161 | Map> interfaceIdUsersMap = userInterfaceInfoList.stream().collect(Collectors.groupingBy(UserInterfaceInfo::getInterfaceId)); 162 | //计算每一个接口的调用次数 163 | interfaceIdUsersMap.forEach((interfaceId, userInterfaceInfos) -> { 164 | InvokeCountVo invokeCountVo = new InvokeCountVo(); 165 | InterfaceInfo interfaceInfo = interfaceService.getById(interfaceId); 166 | invokeCountVo.setName(interfaceInfo.getName()); 167 | int count = 0; 168 | //将每一组的调用次数进行累加 169 | for (UserInterfaceInfo userInterfaceInfo : userInterfaceInfos) { 170 | count += userInterfaceInfo.getTotalNum(); 171 | } 172 | invokeCountVo.setCount(count); 173 | invokeCountVoList.add(invokeCountVo); 174 | }); 175 | return invokeCountVoList; 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /byapi-server/src/main/java/com/example/server/service/impl/UserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.example.server.service.impl; 2 | 3 | import cn.hutool.core.bean.BeanUtil; 4 | import cn.hutool.core.date.DateUtil; 5 | import cn.hutool.core.io.IoUtil; 6 | import cn.hutool.core.util.RandomUtil; 7 | import cn.hutool.core.util.StrUtil; 8 | import cn.hutool.crypto.digest.DigestUtil; 9 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 10 | import com.baomidou.mybatisplus.core.metadata.IPage; 11 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 12 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 13 | import com.example.common.constant.CommonConsts; 14 | import com.example.common.constant.UserConsts; 15 | import com.example.common.enums.ErrorCode; 16 | import com.example.common.enums.RoleEnum; 17 | import com.example.common.exception.BusinessException; 18 | import com.example.common.model.dto.*; 19 | import com.example.common.model.entity.User; 20 | import com.example.common.model.vo.KeyVo; 21 | import com.example.common.model.vo.UserVo; 22 | import com.example.common.utils.PageBean; 23 | import com.example.server.mapper.UserMapper; 24 | import com.example.server.service.UserService; 25 | import lombok.extern.slf4j.Slf4j; 26 | import org.apache.commons.lang3.StringUtils; 27 | import org.springframework.beans.factory.annotation.Value; 28 | import org.springframework.mail.javamail.JavaMailSenderImpl; 29 | import org.springframework.mail.javamail.MimeMessageHelper; 30 | import org.springframework.stereotype.Service; 31 | import org.springframework.web.multipart.MultipartFile; 32 | 33 | import javax.annotation.Resource; 34 | import javax.mail.Session; 35 | import javax.mail.internet.MimeMessage; 36 | import javax.servlet.http.HttpServletRequest; 37 | import javax.servlet.http.HttpServletResponse; 38 | import javax.servlet.http.HttpSession; 39 | import java.io.*; 40 | import java.text.DateFormat; 41 | import java.util.Date; 42 | import java.util.HashMap; 43 | import java.util.Map; 44 | import java.util.UUID; 45 | import java.util.concurrent.ScheduledExecutorService; 46 | import java.util.concurrent.ScheduledThreadPoolExecutor; 47 | import java.util.concurrent.ThreadPoolExecutor; 48 | import java.util.concurrent.TimeUnit; 49 | 50 | /** 51 | * @author by 52 | */ 53 | @Service 54 | @Slf4j 55 | public class UserServiceImpl extends ServiceImpl 56 | implements UserService { 57 | 58 | @Value("${byapi.server.path.domain}") 59 | private String domain; 60 | @Value("${byapi.server.path.address}") 61 | private String address; 62 | 63 | /** 64 | * 邮件发送类 65 | */ 66 | @Resource 67 | private JavaMailSenderImpl javaMailSender; 68 | 69 | @Resource 70 | private UserMapper userMapper; 71 | 72 | /** 73 | * 创建线程池 74 | */ 75 | private final ScheduledExecutorService scheduledExecutorService = new ScheduledThreadPoolExecutor(10, new ThreadPoolExecutor.AbortPolicy()); 76 | 77 | @Override 78 | public UserVo userLogin(LoginDto loginDto, HttpServletRequest request) { 79 | String userAccount = loginDto.getUserAccount(); 80 | String userPassword = loginDto.getUserPassword(); 81 | //判断参数是否合法 82 | if (StringUtils.isAnyBlank(userAccount, userPassword)) { 83 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 84 | } 85 | 86 | //账号长度不能小于4位 87 | if (userAccount.length() < UserConsts.USER_NAME_LENGTH) { 88 | throw new BusinessException(ErrorCode.PARAMS_ERROR, UserConsts.USER_NAME_ERROR); 89 | } 90 | 91 | //密码长度不能小于8位 92 | if (userPassword.length() < UserConsts.USER_PASSWORD_LENGTH) { 93 | throw new BusinessException(ErrorCode.PARAMS_ERROR, UserConsts.USER_PASSWORD_ERROR); 94 | } 95 | 96 | //判断用户是否存在 97 | User user = this.lambdaQuery() 98 | .eq(User::getUserAccount, userAccount) 99 | .one(); 100 | if (user == null) { 101 | throw new BusinessException(ErrorCode.PARAMS_ERROR, UserConsts.USER_PARAMS_ERROR); 102 | } 103 | 104 | //判断用户是否被禁用 105 | if (user.getStatus() == 1) { 106 | throw new BusinessException(ErrorCode.PARAMS_ERROR, UserConsts.ACCOUNT_FORBIDDEN); 107 | } 108 | 109 | //判断密码是否正确 110 | String encryptPassword = DigestUtil.md5Hex(userPassword + user.getSalt()); 111 | if (!user.getUserPassword().equals(encryptPassword)) { 112 | throw new BusinessException(ErrorCode.PARAMS_ERROR, UserConsts.USER_PARAMS_ERROR); 113 | } 114 | 115 | //用户信息脱敏 116 | UserVo userVo = new UserVo(); 117 | BeanUtil.copyProperties(user, userVo); 118 | //设置用户登录态 119 | request.getSession().setAttribute(UserConsts.USER_LOGIN_STATE, userVo); 120 | //返回 121 | return userVo; 122 | } 123 | 124 | @Override 125 | public void userRegister(RegisterDto registerDto) { 126 | String userAccount = registerDto.getUserAccount(); 127 | String userPassword = registerDto.getUserPassword(); 128 | String confirmPassword = registerDto.getConfirmPassword(); 129 | //判断参数是否合法 130 | if (StringUtils.isAnyBlank(userAccount, userPassword, confirmPassword)) { 131 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 132 | } 133 | 134 | //判断参数长度是否合法 135 | if (userAccount.length() < UserConsts.USER_NAME_LENGTH) { 136 | throw new BusinessException(ErrorCode.PARAMS_ERROR, UserConsts.USER_NAME_ERROR); 137 | } 138 | if (userPassword.length() < UserConsts.USER_PASSWORD_LENGTH) { 139 | throw new BusinessException(ErrorCode.PARAMS_ERROR, UserConsts.USER_PASSWORD_ERROR); 140 | } 141 | 142 | //判断确认密码和密码是否一致 143 | if (!userPassword.equals(confirmPassword)) { 144 | throw new BusinessException(ErrorCode.PARAMS_ERROR, UserConsts.PASSWORD_NOT_EQUAL); 145 | } 146 | //判断用户名是否存在 147 | User user = this.lambdaQuery() 148 | .eq(User::getUserAccount, userAccount) 149 | .one(); 150 | if (user != null) { 151 | throw new BusinessException(ErrorCode.PARAMS_ERROR, UserConsts.USER_NAME_EXIST); 152 | } 153 | 154 | //生成一个随机的盐 155 | String salt = RandomUtil.randomString(4); 156 | //对密码进行加密 157 | String encryptPassword = DigestUtil.md5Hex(userPassword + salt); 158 | //插入用户数据 159 | user = new User(); 160 | user.setUserAccount(userAccount); 161 | user.setUserName(userAccount); 162 | user.setUserPassword(encryptPassword); 163 | user.setUserRole(RoleEnum.USER.getRole()); 164 | user.setSalt(salt); 165 | this.save(user); 166 | } 167 | 168 | @Override 169 | public UserVo getLoginUser(HttpServletRequest request) { 170 | //获取用户信息 171 | Object object = request.getSession().getAttribute(UserConsts.USER_LOGIN_STATE); 172 | UserVo userVo = (UserVo) object; 173 | if (userVo == null) { 174 | throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR); 175 | } 176 | return userVo; 177 | } 178 | 179 | @Override 180 | public void updateUser(UserUpdateDto userUpdateDto, HttpServletRequest request) { 181 | Long id = userUpdateDto.getId(); 182 | String userAccount = userUpdateDto.getUserAccount(); 183 | String email = userUpdateDto.getEmail(); 184 | Integer status = userUpdateDto.getStatus(); 185 | //判断部分参数是否合法 186 | if (id == null) { 187 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 188 | } 189 | if (StrUtil.isBlank(userAccount) && StrUtil.isBlank(email)) { 190 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 191 | } 192 | 193 | //查询邮箱是否存在 194 | User user = this.lambdaQuery() 195 | .eq(User::getEmail, email) 196 | .one(); 197 | 198 | //获取当前登录用户 199 | UserVo userVo = this.getLoginUser(request); 200 | //如果邮箱存在且邮箱为其他用户所有,则抛出异常 201 | if (user != null && !userVo.getId().equals(user.getId())) { 202 | throw new BusinessException(ErrorCode.PARAMS_ERROR, UserConsts.EMAIL_EXIST); 203 | } 204 | if (status == null) { 205 | userUpdateDto.setStatus(0); 206 | } 207 | //更新 208 | user = new User(); 209 | BeanUtil.copyProperties(userUpdateDto, user); 210 | this.updateById(user); 211 | } 212 | 213 | @Override 214 | public PageBean listUsersByPage(UserPageDto userPageDto) { 215 | // 构建分页条件 216 | IPage pageCondition = new Page<>(userPageDto.getCurrent(), userPageDto.getPageSize()); 217 | // 查询 218 | IPage page = userMapper.listUsersByPage(pageCondition, userPageDto); 219 | // 返回 220 | return PageBean.of(page.getTotal(), page.getRecords()); 221 | } 222 | 223 | @Override 224 | public void alterStatus(Long id, Integer status) { 225 | //判断参数是否合法 226 | if (id <= 0 || status < 0 || status > 1) { 227 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 228 | } 229 | //获取用户数据 230 | User user = this.getById(id); 231 | if (user == null) { 232 | throw new BusinessException(ErrorCode.NOT_FOUND_ERROR); 233 | } 234 | //判断状态是否一样 235 | if (user.getStatus().equals(status)) { 236 | return; 237 | } 238 | //更新状态 239 | user.setStatus(status); 240 | this.updateById(user); 241 | } 242 | 243 | @Override 244 | public String uploadAvatar(MultipartFile multipartFile) { 245 | //判断文件名是否为空 246 | String originalFilename = multipartFile.getOriginalFilename(); 247 | if (StrUtil.isBlank(originalFilename)) { 248 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 249 | } 250 | //判断图片后缀是否存在 251 | String suffix = originalFilename.substring(originalFilename.lastIndexOf(".")); 252 | if (StrUtil.isBlank(suffix)) { 253 | throw new BusinessException(ErrorCode.PARAMS_ERROR, CommonConsts.IMAGE_FORMAT_ERROR); 254 | } 255 | //生成随机文件名 256 | String newFileName = UUID.randomUUID().toString().replace("-", "") + suffix; 257 | //上传图片 258 | File dest = new File(address + "/" + newFileName); 259 | try { 260 | multipartFile.transferTo(dest); 261 | } catch (Exception e) { 262 | log.error("图片上传失败", e); 263 | throw new BusinessException(ErrorCode.PARAMS_ERROR, CommonConsts.IMAGE_UPLOAD_ERROR); 264 | } 265 | //获取并返回图片请求路径 266 | return domain + "/user/get/avatar/" + newFileName; 267 | } 268 | 269 | @Override 270 | public void getAvatar(String fileName, HttpServletResponse response) { 271 | //获取文件后缀 272 | String suffix = fileName.substring(fileName.lastIndexOf(".") + 1); 273 | //获取图片存放路径 274 | String url = address + "/" + fileName; 275 | //响应图片 276 | response.setContentType("image/" + suffix); 277 | //从服务器中读取图片 278 | try ( 279 | //获取输出流 280 | OutputStream outputStream = response.getOutputStream(); 281 | //获取输入流 282 | FileInputStream fileInputStream = new FileInputStream(url) 283 | ) { 284 | byte[] buffer = new byte[1024]; 285 | int b; 286 | while ((b = fileInputStream.read(buffer)) != -1) { 287 | //将图片以字节流形式写入输出流 288 | outputStream.write(buffer, 0, b); 289 | } 290 | } catch (IOException e) { 291 | log.error("文件读取失败", e); 292 | throw new BusinessException(ErrorCode.PARAMS_ERROR, CommonConsts.IMAGE_READ_ERROR); 293 | } 294 | } 295 | 296 | @Override 297 | public KeyVo applyKey(HttpServletRequest request) { 298 | //获取登录用户ID 299 | UserVo userVo = this.getLoginUser(request); 300 | Long userId = userVo.getId(); 301 | //判断用户是否存在 302 | User user = this.getById(userId); 303 | if (user == null) { 304 | throw new BusinessException(ErrorCode.NOT_FOUND_ERROR); 305 | } 306 | //给用户生成随机密钥 307 | String accessKey = RandomUtil.randomString(32); 308 | String secretKey = RandomUtil.randomString(32); 309 | //保存密钥 310 | user.setAccessKey(accessKey); 311 | user.setSecretKey(secretKey); 312 | this.updateById(user); 313 | //返回生成的密钥 314 | KeyVo keyVo = new KeyVo(); 315 | keyVo.setAccessKey(accessKey); 316 | keyVo.setSecretKey(secretKey); 317 | return keyVo; 318 | } 319 | 320 | @Override 321 | public void sendEmail(String email, HttpServletRequest request) { 322 | HttpSession session = request.getSession(); 323 | //随机生成验证码 324 | String verCode = RandomUtil.randomNumbers(6); 325 | //发送时间 326 | String time = DateUtil.formatDateTime(new Date()); 327 | //保存验证码的map 328 | Map map = new HashMap<>(4); 329 | map.put(UserConsts.CODE, verCode); 330 | map.put(UserConsts.EMAIL, email); 331 | //验证码和邮箱一起放入session 332 | session.setAttribute(UserConsts.VER_CODE, map); 333 | Object object = session.getAttribute(UserConsts.VER_CODE); 334 | @SuppressWarnings("unchecked") 335 | Map codeMap = (Map) object; 336 | //创建计时线程 337 | try { 338 | //5分钟后移除验证码 339 | scheduledExecutorService.schedule(() -> { 340 | if (email.equals(codeMap.get(UserConsts.EMAIL))) { 341 | session.removeAttribute(UserConsts.VER_CODE); 342 | } 343 | }, 5, TimeUnit.MINUTES); 344 | } catch (Exception e) { 345 | throw new BusinessException(ErrorCode.PARAMS_ERROR, UserConsts.DELAY_TASK_ERROR); 346 | } 347 | //发送邮件 348 | MimeMessage mimeMessage; 349 | MimeMessageHelper helper; 350 | try { 351 | // 解决本地DNS未配置 ip->域名场景下,邮件发送太慢的问题 352 | System.getProperties().setProperty("mail.mime.address.usecanonicalhostname", "false"); 353 | //发送复杂的邮件 354 | mimeMessage = javaMailSender.createMimeMessage(); 355 | Session messageSession = mimeMessage.getSession(); 356 | //解决本地DNS未配置 ip->域名场景下,邮件发送太慢的问题 357 | messageSession.getProperties().setProperty("mail.smtp.localhost", "myComputer"); 358 | //组装 359 | helper = new MimeMessageHelper(mimeMessage, true); 360 | //邮件标题 361 | helper.setSubject("【By API】 验证码"); 362 | //ture为支持识别html标签 363 | helper.setText("

\n" + 364 | "\t亲爱的用户: \n" + 365 | "

\n" + 366 | "

\n" + 367 | "\t        您好!您正在进行邮箱验证,本次请求的验证码为: " + verCode + ",本验证码5分钟内有效,请勿泄露和转发。如非本人操作,请忽略该邮件。\n" + 368 | "

\n" + 369 | "

\n" + 370 | "\tBy API \n" + 371 | "

\n" + 372 | "

\n" + 373 | "\t" + time + " \n" + 374 | "

", true); 375 | //收件人 376 | helper.setTo(email); 377 | //发送方 378 | helper.setFrom("1296800094@qq.com"); 379 | //异步发送邮件 380 | scheduledExecutorService.execute(() -> javaMailSender.send(mimeMessage)); 381 | } catch (Exception e) { 382 | //邮箱是无效的,或者发送失败 383 | throw new BusinessException(ErrorCode.PARAMS_ERROR, UserConsts.SEND_MAIL_ERROR); 384 | } 385 | } 386 | 387 | @Override 388 | public UserVo emailLogin(EmailDto emailDto, HttpServletRequest request) { 389 | String email = emailDto.getEmail(); 390 | String verCode = emailDto.getVerCode(); 391 | if (StringUtils.isAnyBlank(email, verCode)) { 392 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 393 | } 394 | //判断邮箱是否存在 395 | User user = this.lambdaQuery() 396 | .eq(User::getEmail, email) 397 | .one(); 398 | if (user == null) { 399 | throw new BusinessException(ErrorCode.PARAMS_ERROR, UserConsts.EMAIL_PARAMS_ERROR); 400 | } 401 | //判断用户是否被禁用 402 | if (user.getStatus() == 1) { 403 | throw new BusinessException(ErrorCode.PARAMS_ERROR, UserConsts.ACCOUNT_FORBIDDEN); 404 | } 405 | //获取session中的验证码 406 | Object object = request.getSession().getAttribute(UserConsts.VER_CODE); 407 | @SuppressWarnings("unchecked") 408 | Map map = (Map) object; 409 | String sEmail = map.get(UserConsts.EMAIL); 410 | String code = map.get(UserConsts.CODE); 411 | //校验邮箱和验证码 412 | if (!email.equals(sEmail) || !verCode.equals(code)) { 413 | throw new BusinessException(ErrorCode.PARAMS_ERROR, UserConsts.EMAIL_PARAMS_ERROR); 414 | } 415 | //用户信息脱敏 416 | UserVo userVo = new UserVo(); 417 | BeanUtil.copyProperties(user, userVo); 418 | //保存用户登录态 419 | request.getSession().setAttribute(UserConsts.USER_LOGIN_STATE, userVo); 420 | return userVo; 421 | } 422 | 423 | @Override 424 | public void emailRegister(EmailDto emailDto) { 425 | String email = emailDto.getEmail(); 426 | String verCode = emailDto.getVerCode(); 427 | if (StringUtils.isAnyBlank(email, verCode)) { 428 | throw new BusinessException(ErrorCode.PARAMS_ERROR); 429 | } 430 | //判断邮箱是否存在 431 | User user = this.lambdaQuery() 432 | .eq(User::getEmail, email) 433 | .one(); 434 | if (user != null) { 435 | throw new BusinessException(ErrorCode.PARAMS_ERROR, UserConsts.EMAIL_PARAMS_ERROR); 436 | } 437 | //插入数据 438 | user = new User(); 439 | user.setEmail(email); 440 | user.setStatus(0); 441 | user.setUserRole(RoleEnum.USER.getRole()); 442 | user.setUserName(email); 443 | this.save(user); 444 | } 445 | 446 | @Override 447 | public KeyVo getKeyById(HttpServletRequest request) { 448 | UserVo userVo = this.getLoginUser(request); 449 | Long userId = userVo.getId(); 450 | User user = this.lambdaQuery() 451 | .eq(User::getId, userId) 452 | .one(); 453 | KeyVo keyVo = new KeyVo(); 454 | keyVo.setAccessKey(user.getAccessKey()); 455 | keyVo.setSecretKey(user.getSecretKey()); 456 | return keyVo; 457 | } 458 | 459 | @Override 460 | public void downloadJar(HttpServletResponse response) { 461 | try { 462 | //设置响应类型 463 | response.setContentType("application/java-archive"); 464 | //设置响应头,指定下载的文件名 465 | response.setHeader("Content-Disposition", "attachment; filename=byapi-sdk.jar"); 466 | //指定jar包路径 467 | String filePath = "D:/idea/project/byapi-backend/byapi-sdk/target/byapi-sdk-0.0.1-SNAPSHOT.jar"; 468 | File jarFile = new File(filePath); 469 | try (InputStream inputStream = new FileInputStream(jarFile); 470 | OutputStream outputStream = response.getOutputStream()) { 471 | //将jar包写入响应体中 472 | IoUtil.copy(inputStream, outputStream); 473 | } catch (IOException e) { 474 | throw new BusinessException(ErrorCode.PARAMS_ERROR, CommonConsts.SDK_DOWNLOAD_ERROR); 475 | } 476 | } catch (Exception e) { 477 | throw new BusinessException(ErrorCode.PARAMS_ERROR, CommonConsts.SDK_DOWNLOAD_ERROR); 478 | } 479 | } 480 | } 481 | 482 | 483 | 484 | 485 | -------------------------------------------------------------------------------- /byapi-server/src/main/java/com/example/server/task/CacheTask.java: -------------------------------------------------------------------------------- 1 | package com.example.server.task; 2 | 3 | import com.example.common.constant.CommonConsts; 4 | import com.example.common.enums.ErrorCode; 5 | import com.example.common.exception.BusinessException; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.data.redis.core.RedisTemplate; 8 | import org.springframework.data.redis.core.ZSetOperations; 9 | import org.springframework.scheduling.annotation.Scheduled; 10 | import org.springframework.stereotype.Component; 11 | import org.springframework.util.CollectionUtils; 12 | 13 | import javax.annotation.Resource; 14 | import java.util.Set; 15 | 16 | /** 17 | * 删除过期随机数定时任务 18 | * 19 | * @author by 20 | */ 21 | @Component 22 | @Slf4j 23 | public class CacheTask { 24 | 25 | @Resource 26 | private RedisTemplate redisTemplate; 27 | 28 | /** 29 | * 每一分钟检查一次缓存,将过期随机数删除,指定过期时间为10分钟 30 | */ 31 | @Scheduled(cron = "0 * * * * ? ") 32 | public void deleteExpireCache() { 33 | log.info("task begin ..."); 34 | //判断key是否存在 35 | if (Boolean.FALSE.equals(redisTemplate.hasKey(CommonConsts.NONCE_KEY))) { 36 | return; 37 | } 38 | //遍历zSet中的每一个随机数,判断是否过期 39 | ZSetOperations zSetOperations = redisTemplate.opsForZSet(); 40 | Set> typedTuples = zSetOperations.rangeWithScores(CommonConsts.NONCE_KEY, 0, -1); 41 | if (CollectionUtils.isEmpty(typedTuples)) { 42 | return; 43 | } 44 | for (ZSetOperations.TypedTuple tuple : typedTuples) { 45 | Object value = tuple.getValue(); 46 | Double score = tuple.getScore(); 47 | long currentTimeMillis = System.currentTimeMillis(); 48 | //当时间间隔超过10分钟进行删除 49 | if (score != null && currentTimeMillis / 1000.0 - score.longValue() > 10 * 60) { 50 | try { 51 | zSetOperations.remove(CommonConsts.NONCE_KEY, value); 52 | log.info("del expire nonce:{}", value); 53 | } catch (Exception e) { 54 | log.error("redis delete expire cache error", e); 55 | throw new BusinessException(ErrorCode.PARAMS_ERROR, CommonConsts.CACHE_DEL_ERROR); 56 | } 57 | } 58 | } 59 | log.info("task end ..."); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /byapi-server/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 9000 3 | 4 | spring: 5 | datasource: 6 | driver-class-name: com.mysql.cj.jdbc.Driver 7 | username: root 8 | password: root 9 | url: jdbc:mysql://localhost:3306/byapi?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai 10 | jackson: 11 | time-zone: GMT+8 12 | date-format: "yyyy-MM-dd HH:mm:ss" 13 | mvc: 14 | pathmatch: 15 | matching-strategy: ant_path_matcher 16 | servlet: 17 | path: /api 18 | 19 | mail: 20 | username: # 此处填自己的邮箱 21 | # 授权码 22 | password: # 此处填自己的邮箱授权码 23 | host: smtp.qq.com 24 | default-encoding: utf-8 25 | # 开启加密验证 26 | properties: 27 | mail: 28 | smtp: 29 | ssl: 30 | enabled: true 31 | # 允许循环依赖 32 | main: 33 | allow-circular-references: true 34 | 35 | # redis配置 36 | redis: 37 | host: localhost 38 | port: 6379 39 | 40 | 41 | mybatis-plus: 42 | configuration: 43 | log-impl: org.apache.ibatis.logging.stdout.StdOutImpl 44 | global-config: 45 | db-config: 46 | logic-delete-field: isDeleted 47 | logic-delete-value: 1 48 | logic-not-delete-value: 0 49 | 50 | byapi: 51 | server: 52 | path: 53 | domain: http://localhost:9000/api 54 | address: D:\idea\project\byapi-backend\byapi-server\src\main\resources\images 55 | 56 | dubbo: 57 | application: 58 | name: provider 59 | protocol: 60 | name: dubbo 61 | port: -1 62 | registry: 63 | address: nacos://localhost:8848 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /byapi-server/src/main/resources/images/2e6b1467dae840a1ba650e682652e07d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LUBAIYU/byapi-backend/94eb9d9e5e564017b0690ed4212863a460c51b24/byapi-server/src/main/resources/images/2e6b1467dae840a1ba650e682652e07d.png -------------------------------------------------------------------------------- /byapi-server/src/main/resources/images/7b3b41a5fe5041c78b6fe619a8910373.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LUBAIYU/byapi-backend/94eb9d9e5e564017b0690ed4212863a460c51b24/byapi-server/src/main/resources/images/7b3b41a5fe5041c78b6fe619a8910373.jpg -------------------------------------------------------------------------------- /byapi-server/src/main/resources/images/ebcae2156c3c4489bc1a2cc94c2c5956.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LUBAIYU/byapi-backend/94eb9d9e5e564017b0690ed4212863a460c51b24/byapi-server/src/main/resources/images/ebcae2156c3c4489bc1a2cc94c2c5956.png -------------------------------------------------------------------------------- /byapi-server/src/main/resources/mapper/InterfaceInfoMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | id,`name`,`description`, 24 | url,method,request_params, 25 | request_header,response_header,`status`, 26 | create_time,update_time,is_deleted 27 | 28 | 29 | -------------------------------------------------------------------------------- /byapi-server/src/main/resources/mapper/UserInterfaceMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | id,user_id,interface_id, 20 | total_num,left_num,create_time, 21 | update_time,is_deleted 22 | 23 | 24 | -------------------------------------------------------------------------------- /byapi-server/src/main/resources/mapper/UserMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | id,user_name,user_account, 26 | user_avatar,gender,`status`, 27 | user_role,user_password,salt, 28 | access_key,secret_key,create_time, 29 | update_time,is_deleted 30 | 31 | 32 | 53 | 54 | -------------------------------------------------------------------------------- /byapi-server/src/test/java/com/example/ByapiServerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import com.example.client.ByApiClient; 4 | import com.example.common.utils.TokenBucketLimiter; 5 | import com.example.server.ByapiServerApplication; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.junit.jupiter.api.Test; 8 | import org.springframework.boot.test.context.SpringBootTest; 9 | 10 | import javax.annotation.Resource; 11 | import java.util.concurrent.CountDownLatch; 12 | import java.util.concurrent.ExecutorService; 13 | import java.util.concurrent.Executors; 14 | import java.util.concurrent.atomic.AtomicInteger; 15 | 16 | @SpringBootTest(classes = {ByapiServerApplication.class}) 17 | @Slf4j 18 | class ByapiServerApplicationTests { 19 | 20 | @Resource 21 | private ByApiClient byApiClient; 22 | @Resource 23 | private TokenBucketLimiter bucketLimiter; 24 | 25 | //线程池,用于多线程模拟测试 26 | private ExecutorService pool = Executors.newFixedThreadPool(10); 27 | 28 | @Test 29 | void contextLoads() { 30 | System.out.println(byApiClient.getName("张三")); 31 | } 32 | 33 | @Test 34 | void testLimited() { 35 | // 被限制的次数 36 | AtomicInteger limited = new AtomicInteger(0); 37 | // 线程数 38 | final int threads = 2; 39 | // 每条线程的执行轮数 40 | final int turns = 20; 41 | 42 | 43 | // 同步器 44 | CountDownLatch countDownLatch = new CountDownLatch(threads); 45 | long start = System.currentTimeMillis(); 46 | for (int i = 0; i < threads; i++) { 47 | pool.submit(() -> 48 | { 49 | try { 50 | 51 | for (int j = 0; j < turns; j++) { 52 | 53 | boolean intercepted = bucketLimiter.isLimited(); 54 | if (intercepted) { 55 | // 被限制的次数累积 56 | limited.getAndIncrement(); 57 | } 58 | 59 | Thread.sleep(200); 60 | } 61 | 62 | 63 | } catch (Exception e) { 64 | e.printStackTrace(); 65 | } 66 | //等待所有线程结束 67 | countDownLatch.countDown(); 68 | 69 | }); 70 | } 71 | try { 72 | countDownLatch.await(); 73 | } catch (InterruptedException e) { 74 | e.printStackTrace(); 75 | } 76 | float time = (System.currentTimeMillis() - start) / 1000F; 77 | //输出统计结果 78 | 79 | log.info("限制的次数为:" + limited.get() + 80 | ",通过的次数为:" + (threads * turns - limited.get())); 81 | log.info("限制的比例为:" + (float) limited.get() / (float) (threads * turns)); 82 | log.info("运行的时长为:" + time); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.example 8 | byapi-backend 9 | 1.0-SNAPSHOT 10 | pom 11 | 12 | byapi-common 13 | byapi-gateway 14 | byapi-interface 15 | byapi-server 16 | byapi-sdk 17 | 18 | 19 | 20 | 8 21 | 8 22 | UTF-8 23 | 24 | 25 | -------------------------------------------------------------------------------- /sql/byapi.sql: -------------------------------------------------------------------------------- 1 | create database byapi; 2 | 3 | use byapi; 4 | 5 | create table if not exists interface 6 | ( 7 | id bigint auto_increment comment '主键' 8 | primary key, 9 | name varchar(256) not null comment '名称', 10 | description varchar(256) null comment '描述', 11 | url varchar(512) not null comment '接口地址', 12 | method varchar(256) not null comment '请求类型', 13 | request_params text null comment '请求参数', 14 | request_header text null comment '请求头', 15 | response_header text null comment '响应头', 16 | status int default 0 not null comment '接口状态(0-关闭,1-开启)', 17 | code_example text null, 18 | create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间', 19 | update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间', 20 | is_deleted tinyint default 0 not null comment '是否删除(0-未删, 1-已删)' 21 | ) 22 | comment '接口信息' engine = InnoDB; 23 | 24 | create table if not exists user 25 | ( 26 | id bigint auto_increment comment 'id' 27 | primary key, 28 | user_name varchar(256) null comment '用户昵称', 29 | user_account varchar(256) null comment '账号', 30 | user_avatar varchar(1024) null comment '用户头像', 31 | email varchar(256) null comment '用户邮箱,用于邮箱登录', 32 | gender tinyint null comment '性别(0-男,1-女)', 33 | status tinyint default 0 not null comment '用户状态(0-启用,1-禁用)', 34 | user_role varchar(256) default 'user' not null comment '用户角色:user / admin', 35 | user_password varchar(512) null comment '密码', 36 | salt varchar(10) null comment '盐,用于加密', 37 | access_key varchar(512) null comment 'accessKey', 38 | secret_key varchar(512) null comment 'secretKey', 39 | create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间', 40 | update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间', 41 | is_deleted tinyint default 0 not null comment '是否删除', 42 | constraint uni_userAccount 43 | unique (user_account), 44 | constraint user_pk 45 | unique (email) 46 | ) 47 | comment '用户表' engine = InnoDB; 48 | 49 | create table if not exists user_interface 50 | ( 51 | id bigint auto_increment comment '主键' 52 | primary key, 53 | user_id bigint not null comment '调用接口用户ID', 54 | interface_id bigint not null comment '接口ID', 55 | total_num int default 0 not null comment '总调用次数', 56 | left_num int default 0 not null comment '剩余调用次数', 57 | create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间', 58 | update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间', 59 | is_deleted tinyint default 0 not null comment '是否删除(0-未删, 1-已删)' 60 | ) 61 | comment '用户调用接口关系' engine = InnoDB; 62 | 63 | --------------------------------------------------------------------------------