Ver código fonte

feat:开放API平台项目初始化

yang yi 11 meses atrás
commit
419b71d26e
35 arquivos alterados com 2304 adições e 0 exclusões
  1. 25 0
      .gitignore
  2. 76 0
      pom.xml
  3. 33 0
      sql/init.sql
  4. 18 0
      src/main/java/space/anyi/openAPI/Application.java
  5. 31 0
      src/main/java/space/anyi/openAPI/config/MybatisplusConfig.java
  6. 89 0
      src/main/java/space/anyi/openAPI/config/SecurityConfig.java
  7. 67 0
      src/main/java/space/anyi/openAPI/config/SwaggerConfig.java
  8. 22 0
      src/main/java/space/anyi/openAPI/constant/SystemConstants.java
  9. 109 0
      src/main/java/space/anyi/openAPI/controller/UserController.java
  10. 43 0
      src/main/java/space/anyi/openAPI/exception/SystemException.java
  11. 85 0
      src/main/java/space/anyi/openAPI/filter/JWTAuthenticationTokenFilter.java
  12. 30 0
      src/main/java/space/anyi/openAPI/handler/exception/GlobalExceptionHandler.java
  13. 37 0
      src/main/java/space/anyi/openAPI/handler/mybatispuls/MyMetaObjectHandler.java
  14. 33 0
      src/main/java/space/anyi/openAPI/handler/security/AccessDeniedHandlerImpl.java
  15. 44 0
      src/main/java/space/anyi/openAPI/handler/security/AuthenticationEntryPointImpl.java
  16. 19 0
      src/main/java/space/anyi/openAPI/mapper/UserMapper.java
  17. 36 0
      src/main/java/space/anyi/openAPI/model/PageVO.java
  18. 174 0
      src/main/java/space/anyi/openAPI/model/ResponseResult.java
  19. 65 0
      src/main/java/space/anyi/openAPI/model/user/LoginUserDetails.java
  20. 250 0
      src/main/java/space/anyi/openAPI/model/user/User.java
  21. 75 0
      src/main/java/space/anyi/openAPI/model/user/UserInfo.java
  22. 89 0
      src/main/java/space/anyi/openAPI/model/user/dto/UserDTO.java
  23. 77 0
      src/main/java/space/anyi/openAPI/model/user/vo/UserVO.java
  24. 12 0
      src/main/java/space/anyi/openAPI/service/PermissionService.java
  25. 24 0
      src/main/java/space/anyi/openAPI/service/UserService.java
  26. 25 0
      src/main/java/space/anyi/openAPI/service/impl/PermissionServiceImpl.java
  27. 41 0
      src/main/java/space/anyi/openAPI/service/impl/UserDetailsServiceImpl.java
  28. 127 0
      src/main/java/space/anyi/openAPI/service/impl/UserServiceImpl.java
  29. 36 0
      src/main/java/space/anyi/openAPI/util/BeanCopyUtil.java
  30. 112 0
      src/main/java/space/anyi/openAPI/util/JwtUtil.java
  31. 252 0
      src/main/java/space/anyi/openAPI/util/RedisCache.java
  32. 54 0
      src/main/java/space/anyi/openAPI/util/SecurityUtils.java
  33. 44 0
      src/main/java/space/anyi/openAPI/util/WebUtils.java
  34. 26 0
      src/main/resources/application.yaml
  35. 24 0
      src/main/resources/mapper/UserMapper.xml

+ 25 - 0
.gitignore

@@ -0,0 +1,25 @@
+# created by virtualenv automatically
+
+
+**/.idea
+**/node_modules
+**/.gradle
+**/.mvn
+**/*.iml
+**/*.log
+**/*.rar
+**/*.png
+**/*.jpg
+**/*.xls
+**/*.xlsx
+**/*.zip
+**/*.o
+**/*.exe
+**/out/**
+**/target/**
+**/build/**
+/*
+
+!/src
+!/sql
+!.gitignore

+ 76 - 0
pom.xml

@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>space.anyi</groupId>
+    <artifactId>yangyi-open-api-platform</artifactId>
+    <version>1.0.0</version>
+    <description>开放API平台</description>
+
+    <properties>
+        <maven.compiler.source>17</maven.compiler.source>
+        <maven.compiler.target>17</maven.compiler.target>
+    </properties>
+
+    <parent>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <groupId>org.springframework.boot</groupId>
+        <version>2.7.16</version>
+    </parent>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <version>5.1.49</version>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+            <version>3.4.3.4</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.github.xiaoymin</groupId>
+            <artifactId>knife4j-spring-boot-starter</artifactId>
+            <version>2.0.8</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-configuration-processor</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>5.1.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-security</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt</artifactId>
+            <version>0.9.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>

+ 33 - 0
sql/init.sql

@@ -0,0 +1,33 @@
+create database if not exists `open-api-platform`;
+
+USE `open-api-platform`;
+
+-- 创建一个名为users的表,用于存储用户信息
+CREATE TABLE  if NOT EXISTS `user` (
+                                       `id` BIGINT NOT NULL  PRIMARY  KEY COMMENT '用户ID',
+                                       `user_account` VARCHAR(255) NOT NULL COMMENT '用户账号',
+                                       `user_password` VARCHAR(255) NOT NULL COMMENT '用户密码',
+                                       `user_name` VARCHAR(255) NOT NULL COMMENT '用户名称',
+                                       `user_avatar` VARCHAR(1024) DEFAULT NULL COMMENT '用户头像',
+                                       `user_role` CHAR(32) NOT NULL DEFAULT '用户' COMMENT '用户角色',
+                                       `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+                                       `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+                                       `delete_flag` TINYINT(1) NOT NULL DEFAULT '0' COMMENT '删除标志,0:未删除,1:已删除'
+) COMMENT='用户表';
+
+-- 接口信息
+create table if not exists `interface_info`
+(
+    `id` bigint not null auto_increment comment '主键' primary key,
+    `name` varchar(256) not null comment '名称',
+    `description` varchar(256) null comment '描述',
+    `url` varchar(512) not null comment '接口地址',
+    `request_header` text null comment '请求头',
+    `response_header` text null comment '响应头',
+    `status` int default 0 not null comment '接口状态(0-关闭,1-开启)',
+    `method` varchar(256) not null comment '请求类型',
+    `user_id` bigint not null comment '创建人',
+    `create_time` datetime default CURRENT_TIMESTAMP not null comment '创建时间',
+    `update_time` datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
+    `delete_flag` tinyint default 0 not null comment '是否删除(0-未删, 1-已删)'
+) comment '接口信息';

+ 18 - 0
src/main/java/space/anyi/openAPI/Application.java

@@ -0,0 +1,18 @@
+package space.anyi.openAPI;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * @ProjectName: yangyi-open-api-platform
+ * @FileName: Application
+ * @Author: 杨逸
+ * @Data:2025/10/14 15:44
+ * @Description:
+ */
+@SpringBootApplication
+public class Application {
+    public static void main(String[] args) {
+        SpringApplication.run(Application.class, args);
+    }
+}

+ 31 - 0
src/main/java/space/anyi/openAPI/config/MybatisplusConfig.java

@@ -0,0 +1,31 @@
+package space.anyi.openAPI.config;
+
+import com.baomidou.mybatisplus.annotation.DbType;
+import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @ProjectName: BI
+ * @FileName: MybatisplusConfig
+ * @Author: 杨逸
+ * @Data:2024/11/28 19:14
+ * @Description:
+ */
+@Configuration
+@MapperScan("space.anyi.openAPI.mapper")
+public class MybatisplusConfig {
+    @Bean
+    public MybatisPlusInterceptor mybatisPlusInterceptor(){
+        //拦截器
+        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
+        //分页拦截器
+        PaginationInnerInterceptor innerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
+        //设置请求的页面大于最大页后操作,true调回到首页,false 继续请求 默认false
+        innerInterceptor.setOverflow(true);
+        mybatisPlusInterceptor.addInnerInterceptor(innerInterceptor);
+        return mybatisPlusInterceptor;
+    }
+}

+ 89 - 0
src/main/java/space/anyi/openAPI/config/SecurityConfig.java

@@ -0,0 +1,89 @@
+package space.anyi.openAPI.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpMethod;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.web.AuthenticationEntryPoint;
+import org.springframework.security.web.access.AccessDeniedHandler;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+import space.anyi.openAPI.filter.JWTAuthenticationTokenFilter;
+import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
+
+import javax.annotation.Resource;
+
+/**
+ * @ProjectName: BI
+ * @FileName: SecurityConfig
+ * @Author: 杨逸
+ * @Data:2024/11/28 20:02
+ * @Description:
+ */
+@EnableGlobalMethodSecurity(prePostEnabled = true)
+@Configuration
+@EnableSwagger2WebMvc
+public class SecurityConfig extends WebSecurityConfigurerAdapter {
+    @Resource
+    private JWTAuthenticationTokenFilter jwtAuthenticationTokenFilter;
+    @Resource
+    private  AccessDeniedHandler accessDeniedHandler;
+    @Resource
+    private  AuthenticationEntryPoint authenticationEntryPoint;
+    /**
+     * 密码校验方式
+     * @return
+     */
+    @Bean
+    public PasswordEncoder passwordEncoder(){
+        return new BCryptPasswordEncoder();
+    }
+
+    /**
+     * 安全配置
+     * @param http
+     * @throws Exception
+     */
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        http
+                //关闭csrf
+                .csrf().disable()
+                //不通过Session获取SecurityContext
+                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
+                .and()
+                .authorizeRequests()
+                // 对于登录接口 允许匿名访问
+                .antMatchers(HttpMethod.POST,"/user/login","/user/register").anonymous()
+                .antMatchers(HttpMethod.GET,"/swagger/**","/api/**","/v2/**","/v2/api-docs-ext/**","/swagger-resources/**").anonymous()
+                //放行对静态资源的访问
+                .antMatchers(HttpMethod.GET,"/","/*.html","/**/*.css","/**/*.js","/img/**","/fonts/**").permitAll()
+                .antMatchers(HttpMethod.GET,"/user/getUserInfo").permitAll()
+                .antMatchers(HttpMethod.POST,"/user/logout","/user/updatePassword").authenticated()
+                .antMatchers(HttpMethod.POST,"/uploadImage").permitAll()
+                // 除上面外的所有请求全部需要认证访问
+                .anyRequest().authenticated();
+
+        //关闭Security默认的退出接口
+        http.logout().disable();
+        http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
+
+        http.exceptionHandling()
+                .accessDeniedHandler(accessDeniedHandler)
+                .authenticationEntryPoint(authenticationEntryPoint);
+        //允许跨域
+        http.cors();
+    }
+
+
+    @Override
+    @Bean
+    public AuthenticationManager authenticationManagerBean() throws Exception {
+        return super.authenticationManagerBean();
+    }
+}

+ 67 - 0
src/main/java/space/anyi/openAPI/config/SwaggerConfig.java

@@ -0,0 +1,67 @@
+package space.anyi.openAPI.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.Contact;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
+
+/**
+ * @ProjectName: BI
+ * @FileName: SwaggerConfig
+ * @Author: 杨逸
+ * @Data:2024/11/28 11:37
+ * @Description:
+ */
+@Configuration
+@EnableSwagger2WebMvc
+public class SwaggerConfig {
+    @Bean
+    public Docket createRestApi() {
+        return new Docket(DocumentationType.SWAGGER_2)  // DocumentationType.SWAGGER_2 固定的,代表swagger2
+                .groupName("开发环境") // 如果配置多个文档的时候,那么需要配置groupName来分组标识
+                .apiInfo(apiInfo()) // 用于生成API信息
+                .select() // select()函数返回一个ApiSelectorBuilder实例,用来控制接口被swagger做成文档
+                // 扫描指定包下的接口,最为常用
+                .apis(RequestHandlerSelectors.basePackage("space.anyi.openAPI.controller"))
+                //.withClassAnnotation(RestController.class) // 扫描带有指定注解的类下所有接口
+                //.withMethodAnnotation(PostMapping.class) // 扫描带有指定注解的方法接口
+                //.apis(RequestHandlerSelectors.any()) // 扫描所有
+
+                // 选择所有的API,如果你想只为部分API生成文档,可以配置这里
+                .paths(PathSelectors.any()
+                        //.any() // 满足条件的路径,该断言总为true
+                        //.none() // 不满足条件的路径,该断言总为false(可用于生成环境屏蔽 swagger)
+                        //.ant("/user/**") // 满足字符串表达式路径
+                        //.regex("") // 符合正则的路径
+                )
+                .build();
+    }
+
+    /**
+     * 用于定义API主界面的信息,比如可以声明所有的API的总标题、描述、版本
+     * @return
+     */
+    private ApiInfo apiInfo() {
+
+        Contact contact = new Contact(
+                "杨逸", // 作者姓名
+                "http://anyi.space/", // 作者网址
+                "123456789@163.com"); // 作者邮箱
+
+        return new ApiInfoBuilder()
+                .title("openAPI项目API") //  可以用来自定义API的主标题
+                .description("openAPI项目SwaggerAPI管理") // 可以用来描述整体的API
+                //.termsOfServiceUrl("https://www.baidu.com") // 用于定义服务的域名(跳转链接)
+                .version("1.0") // 可以用来定义版本
+                //.license("Swagger-的使用教程")
+                //.licenseUrl("https://blog.csdn.net")
+                .contact(contact)
+                .build(); //
+    }
+}

+ 22 - 0
src/main/java/space/anyi/openAPI/constant/SystemConstants.java

@@ -0,0 +1,22 @@
+package space.anyi.openAPI.constant;
+
+/**
+ * @ProjectName: BI
+ * @FileName: SystemConstants
+ * @Author: 杨逸
+ * @Data:2024/11/28 20:16
+ * @Description:
+ */
+public class SystemConstants {
+
+    /**
+     * 管理员类型用户
+     */
+    public static final String ADMIN = "admin";
+
+    /**
+     * 存入redis用户ID的前缀
+     */
+    public static final String LOGIN_USER_REDIS_KEY = "login:user:";
+
+}

+ 109 - 0
src/main/java/space/anyi/openAPI/controller/UserController.java

@@ -0,0 +1,109 @@
+package space.anyi.openAPI.controller;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.*;
+import space.anyi.openAPI.model.PageVO;
+import space.anyi.openAPI.model.ResponseResult;
+import space.anyi.openAPI.model.user.LoginUserDetails;
+import space.anyi.openAPI.model.user.User;
+import space.anyi.openAPI.model.user.dto.UserDTO;
+import space.anyi.openAPI.model.user.vo.UserVO;
+import space.anyi.openAPI.service.UserService;
+import space.anyi.openAPI.util.BeanCopyUtil;
+import space.anyi.openAPI.util.SecurityUtils;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * @ProjectName: BI
+ * @FileName: UserController
+ * @Author: 杨逸
+ * @Data:2024/11/28 19:52
+ * @Description:
+ */
+@RequestMapping("/user")
+@RestController
+public class UserController {
+    private final static Logger log = LoggerFactory.getLogger(UserController.class);
+    @Resource
+    private UserService userService;
+    @Resource
+    private PasswordEncoder passwordEncoder;
+
+    @PostMapping("/login")
+    public ResponseResult login(@RequestBody User user){
+        return userService.login(user);
+    }
+
+    @PostMapping("/register")
+    public ResponseResult resister(@RequestBody User user){
+        return userService.register(user);
+    }
+
+    @PreAuthorize("@ps.hasRole('用户')")
+    @GetMapping("/getUserInfo")
+    public ResponseResult getUserInfo(){
+        LoginUserDetails loginUser = SecurityUtils.getLoginUser();
+        if (Objects.isNull(loginUser)){
+            return ResponseResult.errorResult(ResponseResult.AppHttpCodeEnum.NEED_LOGIN);
+        }
+        User user = loginUser.getUser();
+        user.setUserPassword("");
+        System.out.println("user = " + user);
+        return ResponseResult.okResult(user);
+    }
+    @PreAuthorize("@ps.hasRole('管理员')")
+    @GetMapping("/page")
+    @ResponseBody
+    public ResponseResult page(Integer currentPage,Integer pageSize,String userName,String userAccount,String userRole){
+        log.info("currentPage:{},pageSize:{},userName:{},userAccount:{}",currentPage,pageSize,userName,userAccount);
+        PageVO page = userService.pageByUsernameAndUseraccount(currentPage, pageSize, userName, userAccount,userRole);
+        return ResponseResult.okResult(page);
+    }
+    @PreAuthorize("@ps.hasRole('用户')")
+    @GetMapping("/{id}")
+    @ResponseBody
+    public ResponseResult getUserById(@PathVariable Long id){
+        User user = userService.getById(id);
+        UserVO userVO = BeanCopyUtil.copyBean(user, UserVO.class);
+        userVO.setId(user.getId().toString());
+        return ResponseResult.okResult(userVO);
+    }
+
+    @PreAuthorize("@ps.hasRole('管理员')")
+    @DeleteMapping("/{ids}")
+    @ResponseBody
+    public ResponseResult deleteUserById(@PathVariable List<Long> ids){
+        userService.removeByIds(ids);
+        return ResponseResult.okResult();
+    }
+
+    @PreAuthorize("@ps.hasRole('管理员')")
+    @PutMapping
+    @ResponseBody
+    public ResponseResult updateUser(@RequestBody UserDTO userDTO){
+        User user = BeanCopyUtil.copyBean(userDTO, User.class);
+        if (StringUtils.hasText(user.getUserPassword())) {
+            user.setUserPassword(passwordEncoder.encode(user.getUserPassword()));
+        }else{
+            user.setUserPassword(passwordEncoder.encode("password"));
+        }
+        userService.updateById(user);
+        return ResponseResult.okResult();
+    }
+
+    @PreAuthorize("@ps.hasRole('管理员')")
+    @PostMapping
+    @ResponseBody
+    public ResponseResult addUser(@RequestBody UserDTO userDTO){
+        userService.addUser(userDTO);
+        return ResponseResult.okResult();
+    }
+
+}

+ 43 - 0
src/main/java/space/anyi/openAPI/exception/SystemException.java

@@ -0,0 +1,43 @@
+package space.anyi.openAPI.exception;
+
+
+import space.anyi.openAPI.model.ResponseResult;
+
+/**
+ * @ProjectName: BI
+ * @FileName: SystemException
+ * @Author: 杨逸
+ * @Data:2024/11/28 20:22
+ * @Description:
+ */
+public class SystemException extends RuntimeException {
+    private int code;
+
+    private String msg;
+
+    public SystemException() {
+        super();
+    }
+    public SystemException(int code, String msg) {
+        super(msg);
+        this.code = code;
+        this.msg = msg;
+    }
+
+
+
+    public int getCode() {
+        return code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public SystemException(ResponseResult.AppHttpCodeEnum httpCodeEnum) {
+        super(httpCodeEnum.getMsg());
+        this.code = httpCodeEnum.getCode();
+        this.msg = httpCodeEnum.getMsg();
+    }
+
+}

+ 85 - 0
src/main/java/space/anyi/openAPI/filter/JWTAuthenticationTokenFilter.java

@@ -0,0 +1,85 @@
+package space.anyi.openAPI.filter;
+
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.jsonwebtoken.Claims;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+import org.springframework.web.filter.OncePerRequestFilter;
+import space.anyi.openAPI.constant.SystemConstants;
+import space.anyi.openAPI.model.ResponseResult;
+import space.anyi.openAPI.model.user.LoginUserDetails;
+import space.anyi.openAPI.model.user.User;
+import space.anyi.openAPI.service.UserService;
+import space.anyi.openAPI.util.JwtUtil;
+import space.anyi.openAPI.util.RedisCache;
+import space.anyi.openAPI.util.WebUtils;
+
+import javax.annotation.Resource;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Objects;
+
+/**
+ * @ProjectName: BI
+ * @FileName: JWTAuthenticationTokenFilter
+ * @Author: 杨逸
+ * @Data:2024/11/28 20:04
+ * @Description:
+ */
+@Component
+public class JWTAuthenticationTokenFilter extends OncePerRequestFilter {
+    private final static Logger log = LoggerFactory.getLogger(JWTAuthenticationTokenFilter.class);
+    @Resource
+    private RedisCache redisCache;
+    @Resource
+    private ObjectMapper objectMapper;
+
+    @Override
+    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
+        //获取token
+        String uri = httpServletRequest.getRequestURI();
+        String token = httpServletRequest.getHeader("token");
+        log.info("token={},\n请求的uri={}",token,uri);
+        if (!StringUtils.hasText(token)) {
+            filterChain.doFilter(httpServletRequest, httpServletResponse);
+            return;
+        }
+        //解析token
+        Claims jwt;
+        try {
+            jwt = JwtUtil.parseJWT(token);
+        } catch (Exception e) {
+            e.printStackTrace();
+            //响应前端,需要登陆
+            ResponseResult errorResult = ResponseResult.errorResult(ResponseResult.AppHttpCodeEnum.NEED_LOGIN);
+
+            WebUtils.renderString(httpServletResponse, objectMapper.writeValueAsString(errorResult));
+            return;
+        }
+        //从redis中获取用户信息
+        LoginUserDetails loginUserDetails = redisCache.getCacheObject(SystemConstants.LOGIN_USER_REDIS_KEY +jwt.getSubject());
+
+        //已退出登陆或登陆已过期
+        if(Objects.isNull(loginUserDetails)){
+            //响应前端,需要登陆
+            ResponseResult errorResult = ResponseResult.errorResult(ResponseResult.AppHttpCodeEnum.NEED_LOGIN);
+            WebUtils.renderString(httpServletResponse, objectMapper.writeValueAsString(errorResult));
+            return;
+        }
+
+        //存入SecurityContextHolder
+        Authentication authenticationToken = new UsernamePasswordAuthenticationToken(loginUserDetails,null,null);
+        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
+        //放行
+        filterChain.doFilter(httpServletRequest,httpServletResponse);
+    }
+}

+ 30 - 0
src/main/java/space/anyi/openAPI/handler/exception/GlobalExceptionHandler.java

@@ -0,0 +1,30 @@
+package space.anyi.openAPI.handler.exception;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import space.anyi.openAPI.exception.SystemException;
+import space.anyi.openAPI.model.ResponseResult;
+
+/**
+ * @ProjectName: BI
+ * @FileName: GlobalExceptionHandler
+ * @Author: 杨逸
+ * @Data:2024/11/28 20:25
+ * @Description:
+ */
+@RestControllerAdvice
+public class GlobalExceptionHandler{
+    private final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
+    @ExceptionHandler(SystemException.class)
+    public ResponseResult systemException(SystemException e){
+        log.error("发生错误:{}",e);
+        return ResponseResult.errorResult(e.getCode(),e.getMsg());
+    }
+    @ExceptionHandler(Exception.class)
+    public ResponseResult systemException(Exception e){
+        log.error("发生错误:{}",e);
+        return ResponseResult.errorResult(ResponseResult.AppHttpCodeEnum.SYSTEM_ERROR.getCode(),e.getMessage());
+    }
+}

+ 37 - 0
src/main/java/space/anyi/openAPI/handler/mybatispuls/MyMetaObjectHandler.java

@@ -0,0 +1,37 @@
+package space.anyi.openAPI.handler.mybatispuls;
+
+import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
+import org.apache.ibatis.reflection.MetaObject;
+import org.springframework.stereotype.Component;
+import space.anyi.openAPI.util.SecurityUtils;
+
+import java.util.Date;
+
+/**
+ * @ProjectName: BI
+ * @FileName: MyMetaObjectHandler
+ * @Author: 杨逸
+ * @Data:2024/11/28 20:41
+ * @Description:
+ */
+@Component
+public class MyMetaObjectHandler implements MetaObjectHandler {
+    @Override
+    public void insertFill(MetaObject metaObject) {
+        Long userId = null;
+        try {
+            userId = SecurityUtils.getUserId();
+        } catch (Exception e) {
+            e.printStackTrace();
+            userId = -1L;//表示是自己创建
+        }
+        System.out.println("插入拦截器触发");
+        this.setFieldValByName("createTime", new Date(), metaObject);
+        this.setFieldValByName("updateTime", new Date(), metaObject);
+    }
+
+    @Override
+    public void updateFill(MetaObject metaObject) {
+        this.setFieldValByName("updateTime", new Date(), metaObject);
+    }
+}

+ 33 - 0
src/main/java/space/anyi/openAPI/handler/security/AccessDeniedHandlerImpl.java

@@ -0,0 +1,33 @@
+package space.anyi.openAPI.handler.security;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.security.web.access.AccessDeniedHandler;
+import org.springframework.stereotype.Component;
+import space.anyi.openAPI.model.ResponseResult;
+import space.anyi.openAPI.util.WebUtils;
+
+import javax.annotation.Resource;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * @ProjectName: BI
+ * @FileName: AccessDeniedHandlerImpl
+ * @Author: 杨逸
+ * @Data:2024/11/28 20:17
+ * @Description:
+ */
+@Component
+public class AccessDeniedHandlerImpl implements AccessDeniedHandler {
+    @Resource
+    private ObjectMapper objectMapper;
+    @Override
+    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
+        e.printStackTrace();
+        ResponseResult responseResult = ResponseResult.errorResult(ResponseResult.AppHttpCodeEnum.NO_OPERATOR_AUTH);
+        WebUtils.renderString(httpServletResponse, objectMapper.writeValueAsString(responseResult));
+    }
+}

+ 44 - 0
src/main/java/space/anyi/openAPI/handler/security/AuthenticationEntryPointImpl.java

@@ -0,0 +1,44 @@
+package space.anyi.openAPI.handler.security;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.security.authentication.InsufficientAuthenticationException;
+import org.springframework.security.authentication.InternalAuthenticationServiceException;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.AuthenticationEntryPoint;
+import org.springframework.stereotype.Component;
+import space.anyi.openAPI.model.ResponseResult;
+import space.anyi.openAPI.util.WebUtils;
+
+import javax.annotation.Resource;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * @ProjectName: BI
+ * @FileName: AuthenticationEntryPointImpl
+ * @Author: 杨逸
+ * @Data:2024/11/28 20:18
+ * @Description:
+ */
+@Component
+public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {
+    @Resource
+    private ObjectMapper objectMapper;
+    @Override
+    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
+        e.printStackTrace();
+        ResponseResult responseResult = null;
+        //针对不同异常,返回对应的信息
+        if (e instanceof InsufficientAuthenticationException) {
+            responseResult = ResponseResult.errorResult(ResponseResult.AppHttpCodeEnum.NO_OPERATOR_AUTH);
+        } else if (e instanceof InternalAuthenticationServiceException) {
+            responseResult = ResponseResult.errorResult(ResponseResult.AppHttpCodeEnum.LOGIN_ERROR);
+        } else {
+            responseResult = ResponseResult.errorResult(ResponseResult.AppHttpCodeEnum.SYSTEM_ERROR.getCode(),e.getMessage());
+        }
+
+        WebUtils.renderString(httpServletResponse, objectMapper.writeValueAsString(responseResult));
+    }
+}

+ 19 - 0
src/main/java/space/anyi/openAPI/mapper/UserMapper.java

@@ -0,0 +1,19 @@
+package space.anyi.openAPI.mapper;
+
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import space.anyi.openAPI.model.user.User;
+
+/**
+* @author 杨逸
+* @description 针对表【user(用户表)】的数据库操作Mapper
+* @createDate 2024-11-28 19:46:42
+* @Entity space.anyi.BI.entity.User
+*/
+public interface UserMapper extends BaseMapper<User> {
+
+}
+
+
+
+

+ 36 - 0
src/main/java/space/anyi/openAPI/model/PageVO.java

@@ -0,0 +1,36 @@
+package space.anyi.openAPI.model;
+
+import java.util.List;
+
+/**
+ * @ProjectName: serve
+ * @FileName: PageVO
+ * @Author: 杨逸
+ * @Data:2024/12/5 10:23
+ * @Description:
+ */
+public class PageVO {
+    private Integer total;
+    private List<Object> records;
+
+    public PageVO(List records, long total) {
+        this.records = records;
+        this.total = (int) total;
+    }
+
+    public Integer getTotal() {
+        return total;
+    }
+
+    public void setTotal(Integer total) {
+        this.total = total;
+    }
+
+    public List<Object> getRecords() {
+        return records;
+    }
+
+    public void setRecords(List<Object> records) {
+        this.records = records;
+    }
+}

+ 174 - 0
src/main/java/space/anyi/openAPI/model/ResponseResult.java

@@ -0,0 +1,174 @@
+package space.anyi.openAPI.model;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+
+import java.io.Serializable;
+
+/**
+ * @Projectname: gditSpringBootLibrary
+ * @Filename: ResponseResult
+ * @Author: 杨逸
+ * @Data:2023/12/14 17:48
+ * @Description: 统一响应实体
+ */
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class ResponseResult<T> implements Serializable {
+    private Integer code;
+    private String msg;
+    private T data;
+
+    public ResponseResult() {
+        this.code = AppHttpCodeEnum.SUCCESS.getCode();
+        this.msg = AppHttpCodeEnum.SUCCESS.getMsg();
+    }
+
+    public ResponseResult(Integer code, T data) {
+        this.code = code;
+        this.data = data;
+    }
+
+    public ResponseResult(Integer code, String msg, T data) {
+        this.code = code;
+        this.msg = msg;
+        this.data = data;
+    }
+
+    public ResponseResult(Integer code, String msg) {
+        this.code = code;
+        this.msg = msg;
+    }
+
+    public static ResponseResult errorResult(int code, String msg) {
+        ResponseResult result = new ResponseResult();
+        return result.error(code, msg);
+    }
+    public static ResponseResult okResult() {
+        ResponseResult result = new ResponseResult();
+        return result;
+    }
+    public static ResponseResult okResult(int code, String msg) {
+        ResponseResult result = new ResponseResult();
+        return result.ok(code, null, msg);
+    }
+    public static ResponseResult okResult(String msg,Object data) {
+        ResponseResult result = new ResponseResult();
+        return result.ok(200, data, msg);
+    }
+
+    public static ResponseResult okResult(Object data) {
+        ResponseResult result = setAppHttpCodeEnum(AppHttpCodeEnum.SUCCESS, AppHttpCodeEnum.SUCCESS.getMsg());
+        if(data!=null) {
+            result.setData(data);
+        }
+        return result;
+    }
+
+    public static ResponseResult errorResult(AppHttpCodeEnum enums){
+        return setAppHttpCodeEnum(enums,enums.getMsg());
+    }
+
+    public static ResponseResult errorResult(AppHttpCodeEnum enums, String msg){
+        return setAppHttpCodeEnum(enums,msg);
+    }
+
+    public static ResponseResult setAppHttpCodeEnum(AppHttpCodeEnum enums){
+        return okResult(enums.getCode(),enums.getMsg());
+    }
+
+    private static ResponseResult setAppHttpCodeEnum(AppHttpCodeEnum enums, String msg){
+        return okResult(enums.getCode(),msg);
+    }
+
+    public ResponseResult<?> error(Integer code, String msg) {
+        this.code = code;
+        this.msg = msg;
+        return this;
+    }
+
+    public ResponseResult<?> ok(Integer code, T data) {
+        this.code = code;
+        this.data = data;
+        return this;
+    }
+
+    public ResponseResult<?> ok(Integer code, T data, String msg) {
+        this.code = code;
+        this.data = data;
+        this.msg = msg;
+        return this;
+    }
+
+    public ResponseResult<?> ok(T data) {
+        this.data = data;
+        return this;
+    }
+
+    public Integer getCode() {
+        return code;
+    }
+
+    public void setCode(Integer code) {
+        this.code = code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+
+    public T getData() {
+        return data;
+    }
+
+    public void setData(T data) {
+        this.data = data;
+    }
+
+    /**
+     * 内部类,响应状态枚举
+     */
+    public enum AppHttpCodeEnum {
+        // 成功
+        SUCCESS(200,"操作成功"),
+        // 登录
+        NEED_LOGIN(401,"需要登录后操作"),
+        NO_OPERATOR_AUTH(403,"无权限操作"),
+        FILE_NOT_NULL(410,"文件不能为空"),
+        FILE_TYPE_ERROR(411,"文件类型错误"),
+        SYSTEM_ERROR(500,"出现错误"),
+        USERNAME_EXIST(501,"用户名已存在"),
+        REQUIRE_USERNAME(502, "必需填写用户名"),
+        LOGIN_ERROR(503,"用户名或密码错误"),
+        USER_NOT_NULL(510,"用户不能为空"),
+        PASSWORD_NOT_NULL(511,"密码不能为空"),
+        PASSWORD_ERROR(514, "密码错误"),
+        USER_NOT_EXIST(515, "用户不存在"),
+        PASSWORD_SAME(516, "新密码不能与旧密码一样"),
+        VERIFY_CODE_ERROR(517, "验证码错误"),
+        USER_STATE_ERROR(518, "用户状态值不正确"),
+        FILE_ERROR(528, "文件读取错误"),
+        FILE_IS_EMPTY_ERROR(529, "文件内容不能为空"),
+        FILE_SIZE_ERROR(412, "文件过大"),
+        RATE_LIMIT_ERROR(429, "请求过于频繁"),;
+
+        private int code;
+        private String msg;
+
+        AppHttpCodeEnum(int code, String errorMessage){
+            this.code = code;
+            this.msg = errorMessage;
+        }
+
+        public int getCode() {
+            return code;
+        }
+
+        public String getMsg() {
+            return msg;
+        }
+    }
+}
+

+ 65 - 0
src/main/java/space/anyi/openAPI/model/user/LoginUserDetails.java

@@ -0,0 +1,65 @@
+package space.anyi.openAPI.model.user;
+
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import java.util.Collection;
+
+/**
+ * @ProjectName: BI
+ * @FileName: LoginUserDetails
+ * @Author: 杨逸
+ * @Data:2024/11/28 20:14
+ * @Description:
+ */
+public class LoginUserDetails implements UserDetails {
+
+    private User user;
+
+    public LoginUserDetails(User user) {
+        this.user = user;
+    }
+
+    @Override
+    public Collection<? extends GrantedAuthority> getAuthorities() {
+        return null;
+    }
+
+    @Override
+    public String getPassword() {
+        return user.getUserPassword();
+    }
+
+    @Override
+    public String getUsername() {
+        return user.getUserAccount();
+    }
+
+    @Override
+    public boolean isAccountNonExpired() {
+        return true;
+    }
+
+    @Override
+    public boolean isAccountNonLocked() {
+        return true;
+    }
+
+    @Override
+    public boolean isCredentialsNonExpired() {
+        return true;
+    }
+
+    @Override
+    public boolean isEnabled() {
+        return true;
+    }
+
+    public User getUser() {
+        return user;
+    }
+
+    public void setUser(User user) {
+        this.user = user;
+    }
+}

+ 250 - 0
src/main/java/space/anyi/openAPI/model/user/User.java

@@ -0,0 +1,250 @@
+package space.anyi.openAPI.model.user;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 用户表
+ * @TableName user
+ */
+@TableName(value ="user")
+public class User implements Serializable {
+    /**
+     * 用户ID
+     */
+    @TableId(type = IdType.ASSIGN_ID)
+    private Long id;
+
+    /**
+     * 用户账号
+     */
+    private String userAccount;
+
+    /**
+     * 用户密码
+     */
+    private String userPassword;
+
+    /**
+     * 用户名称
+     */
+    private String userName;
+
+    /**
+     * 用户头像
+     */
+    private String userAvatar;
+
+    /**
+     * 用户角色
+     */
+    private String userRole = "用户";
+
+    /**
+     * 创建时间
+     */
+    private Date createTime;
+
+    /**
+     * 更新时间
+     */
+    private Date updateTime;
+
+    /**
+     * 删除标志,0:未删除,1:已删除
+     */
+    private Integer deleteFlag;
+
+    @TableField(exist = false)
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 用户ID
+     */
+    public Long getId() {
+        return id;
+    }
+
+    /**
+     * 用户ID
+     */
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    /**
+     * 用户账号
+     */
+    public String getUserAccount() {
+        return userAccount;
+    }
+
+    /**
+     * 用户账号
+     */
+    public void setUserAccount(String userAccount) {
+        this.userAccount = userAccount;
+    }
+
+    /**
+     * 用户密码
+     */
+    public String getUserPassword() {
+        return userPassword;
+    }
+
+    /**
+     * 用户密码
+     */
+    public void setUserPassword(String userPassword) {
+        this.userPassword = userPassword;
+    }
+
+    /**
+     * 用户名称
+     */
+    public String getUserName() {
+        return userName;
+    }
+
+    /**
+     * 用户名称
+     */
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    /**
+     * 用户头像
+     */
+    public String getUserAvatar() {
+        return userAvatar;
+    }
+
+    /**
+     * 用户头像
+     */
+    public void setUserAvatar(String userAvatar) {
+        this.userAvatar = userAvatar;
+    }
+
+    /**
+     * 用户角色
+     */
+    public String getUserRole() {
+        return userRole;
+    }
+
+    /**
+     * 用户角色
+     */
+    public void setUserRole(String userRole) {
+        this.userRole = userRole;
+    }
+
+    /**
+     * 创建时间
+     */
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    /**
+     * 创建时间
+     */
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    /**
+     * 更新时间
+     */
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    /**
+     * 更新时间
+     */
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    /**
+     * 删除标志,0:未删除,1:已删除
+     */
+    public Integer getDeleteFlag() {
+        return deleteFlag;
+    }
+
+    /**
+     * 删除标志,0:未删除,1:已删除
+     */
+    public void setDeleteFlag(Integer deleteFlag) {
+        this.deleteFlag = deleteFlag;
+    }
+
+    @Override
+    public boolean equals(Object that) {
+        if (this == that) {
+            return true;
+        }
+        if (that == null) {
+            return false;
+        }
+        if (getClass() != that.getClass()) {
+            return false;
+        }
+        User other = (User) that;
+        return (this.getId() == null ? other.getId() == null : this.getId().equals(other.getId()))
+            && (this.getUserAccount() == null ? other.getUserAccount() == null : this.getUserAccount().equals(other.getUserAccount()))
+            && (this.getUserPassword() == null ? other.getUserPassword() == null : this.getUserPassword().equals(other.getUserPassword()))
+            && (this.getUserName() == null ? other.getUserName() == null : this.getUserName().equals(other.getUserName()))
+            && (this.getUserAvatar() == null ? other.getUserAvatar() == null : this.getUserAvatar().equals(other.getUserAvatar()))
+            && (this.getUserRole() == null ? other.getUserRole() == null : this.getUserRole().equals(other.getUserRole()))
+            && (this.getCreateTime() == null ? other.getCreateTime() == null : this.getCreateTime().equals(other.getCreateTime()))
+            && (this.getUpdateTime() == null ? other.getUpdateTime() == null : this.getUpdateTime().equals(other.getUpdateTime()))
+            && (this.getDeleteFlag() == null ? other.getDeleteFlag() == null : this.getDeleteFlag().equals(other.getDeleteFlag()));
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((getId() == null) ? 0 : getId().hashCode());
+        result = prime * result + ((getUserAccount() == null) ? 0 : getUserAccount().hashCode());
+        result = prime * result + ((getUserPassword() == null) ? 0 : getUserPassword().hashCode());
+        result = prime * result + ((getUserName() == null) ? 0 : getUserName().hashCode());
+        result = prime * result + ((getUserAvatar() == null) ? 0 : getUserAvatar().hashCode());
+        result = prime * result + ((getUserRole() == null) ? 0 : getUserRole().hashCode());
+        result = prime * result + ((getCreateTime() == null) ? 0 : getCreateTime().hashCode());
+        result = prime * result + ((getUpdateTime() == null) ? 0 : getUpdateTime().hashCode());
+        result = prime * result + ((getDeleteFlag() == null) ? 0 : getDeleteFlag().hashCode());
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(getClass().getSimpleName());
+        sb.append(" [");
+        sb.append("Hash = ").append(hashCode());
+        sb.append(", id=").append(id);
+        sb.append(", userAccount=").append(userAccount);
+        sb.append(", userPassword=").append(userPassword);
+        sb.append(", userName=").append(userName);
+        sb.append(", userAvatar=").append(userAvatar);
+        sb.append(", userRole=").append(userRole);
+        sb.append(", createTime=").append(createTime);
+        sb.append(", updateTime=").append(updateTime);
+        sb.append(", deleteFlag=").append(deleteFlag);
+        sb.append(", serialVersionUID=").append(serialVersionUID);
+        sb.append("]");
+        return sb.toString();
+    }
+}

+ 75 - 0
src/main/java/space/anyi/openAPI/model/user/UserInfo.java

@@ -0,0 +1,75 @@
+package space.anyi.openAPI.model.user;
+
+
+/**
+ * @ProjectName: BI
+ * @FileName: UserInfo
+ * @Author: 杨逸
+ * @Data:2024/11/28 20:36
+ * @Description:
+ */
+public class UserInfo {
+
+
+    /**
+     * 用户账号
+     */
+    private String userAccount;
+
+
+    /**
+     * 用户名称
+     */
+    private String userName;
+
+    /**
+     * 用户头像
+     */
+    private String userAvatar;
+
+    /**
+     * 用户角色
+     */
+    private String userRole;
+
+    public UserInfo(String userAccount, String userName, String userAvatar, String userRole) {
+        this.userAccount = userAccount;
+        this.userName = userName;
+        this.userAvatar = userAvatar;
+        this.userRole = userRole;
+    }
+
+    public String getUserAccount() {
+        return userAccount;
+    }
+
+    public void setUserAccount(String userAccount) {
+        this.userAccount = userAccount;
+    }
+
+
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    public String getUserAvatar() {
+        return userAvatar;
+    }
+
+    public void setUserAvatar(String userAvatar) {
+        this.userAvatar = userAvatar;
+    }
+
+    public String getUserRole() {
+        return userRole;
+    }
+
+    public void setUserRole(String userRole) {
+        this.userRole = userRole;
+    }
+}

+ 89 - 0
src/main/java/space/anyi/openAPI/model/user/dto/UserDTO.java

@@ -0,0 +1,89 @@
+package space.anyi.openAPI.model.user.dto;
+
+
+/**
+ * @ProjectName: serve
+ * @FileName: UserDTO
+ * @Author: 杨逸
+ * @Data:2024/12/5 21:29
+ * @Description:
+ */
+public class UserDTO {
+    /**
+     * 用户ID
+     */
+    private Long id;
+
+    /**
+     * 用户账号
+     */
+    private String userAccount;
+
+    /**
+     * 用户密码
+     */
+    private String userPassword;
+
+    /**
+     * 用户名称
+     */
+    private String userName;
+
+    /**
+     * 用户头像
+     */
+    private String userAvatar;
+
+    /**
+     * 用户角色
+     */
+    private String userRole = "用户";
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getUserAccount() {
+        return userAccount;
+    }
+
+    public void setUserAccount(String userAccount) {
+        this.userAccount = userAccount;
+    }
+
+    public String getUserPassword() {
+        return userPassword;
+    }
+
+    public void setUserPassword(String userPassword) {
+        this.userPassword = userPassword;
+    }
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    public String getUserAvatar() {
+        return userAvatar;
+    }
+
+    public void setUserAvatar(String userAvatar) {
+        this.userAvatar = userAvatar;
+    }
+
+    public String getUserRole() {
+        return userRole;
+    }
+
+    public void setUserRole(String userRole) {
+        this.userRole = userRole;
+    }
+}

+ 77 - 0
src/main/java/space/anyi/openAPI/model/user/vo/UserVO.java

@@ -0,0 +1,77 @@
+package space.anyi.openAPI.model.user.vo;
+
+/**
+ * @ProjectName: serve
+ * @FileName: UserVO
+ * @Author: 杨逸
+ * @Data:2024/12/5 21:09
+ * @Description:
+ */
+public class UserVO {
+    /**
+     * 用户ID
+     */
+    private String id;
+
+    /**
+     * 用户账号
+     */
+    private String userAccount;
+
+
+    /**
+     * 用户名称
+     */
+    private String userName;
+
+    /**
+     * 用户头像
+     */
+    private String userAvatar;
+
+    /**
+     * 用户角色
+     */
+    private String userRole = "用户";
+
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getUserAccount() {
+        return userAccount;
+    }
+
+    public void setUserAccount(String userAccount) {
+        this.userAccount = userAccount;
+    }
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    public String getUserAvatar() {
+        return userAvatar;
+    }
+
+    public void setUserAvatar(String userAvatar) {
+        this.userAvatar = userAvatar;
+    }
+
+    public String getUserRole() {
+        return userRole;
+    }
+
+    public void setUserRole(String userRole) {
+        this.userRole = userRole;
+    }
+}

+ 12 - 0
src/main/java/space/anyi/openAPI/service/PermissionService.java

@@ -0,0 +1,12 @@
+package space.anyi.openAPI.service;
+
+/**
+ * @ProjectName: serve
+ * @FileName: PermissionService
+ * @Author: 杨逸
+ * @Data:2024/12/6 21:43
+ * @Description:
+ */
+public interface PermissionService {
+    boolean hasRole(String role);
+}

+ 24 - 0
src/main/java/space/anyi/openAPI/service/UserService.java

@@ -0,0 +1,24 @@
+package space.anyi.openAPI.service;
+
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import space.anyi.openAPI.model.PageVO;
+import space.anyi.openAPI.model.ResponseResult;
+import space.anyi.openAPI.model.user.User;
+import space.anyi.openAPI.model.user.dto.UserDTO;
+
+/**
+* @author 杨逸
+* @description 针对表【user(用户表)】的数据库操作Service
+* @createDate 2024-11-28 19:46:42
+*/
+public interface UserService extends IService<User> {
+
+    ResponseResult login(User user);
+
+    ResponseResult register(User user);
+
+    PageVO pageByUsernameAndUseraccount(Integer currentPage, Integer pageSize, String userName, String userAccount, String userRole);
+
+    void addUser(UserDTO userDTO);
+}

+ 25 - 0
src/main/java/space/anyi/openAPI/service/impl/PermissionServiceImpl.java

@@ -0,0 +1,25 @@
+package space.anyi.openAPI.service.impl;
+
+import org.springframework.stereotype.Service;
+import space.anyi.openAPI.service.PermissionService;
+import space.anyi.openAPI.util.SecurityUtils;
+
+/**
+ * @ProjectName: serve
+ * @FileName: PermissionServiceImpl
+ * @Author: 杨逸
+ * @Data:2024/12/6 21:45
+ * @Description:
+ */
+@Service("ps")
+public class PermissionServiceImpl implements PermissionService {
+    @Override
+    public boolean hasRole(String role) {
+        String userRole = SecurityUtils.getLoginUser().getUser().getUserRole();
+        if ("管理员".equals(userRole))return true;
+        if (userRole.equals(role)){
+            return true;
+        }
+        return false;
+    }
+}

+ 41 - 0
src/main/java/space/anyi/openAPI/service/impl/UserDetailsServiceImpl.java

@@ -0,0 +1,41 @@
+package space.anyi.openAPI.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.stereotype.Service;
+import space.anyi.openAPI.exception.SystemException;
+import space.anyi.openAPI.mapper.UserMapper;
+import space.anyi.openAPI.model.ResponseResult;
+import space.anyi.openAPI.model.user.LoginUserDetails;
+import space.anyi.openAPI.model.user.User;
+
+import javax.annotation.Resource;
+import java.util.Objects;
+
+/**
+ * @ProjectName: BI
+ * @FileName: UserDetailsServiceImpl
+ * @Author: 杨逸
+ * @Data:2024/11/28 20:20
+ * @Description:
+ */
+@Service
+public class UserDetailsServiceImpl implements UserDetailsService {
+    @Resource
+    private UserMapper userMapper;
+    @Override
+    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
+        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper
+                .eq(User::getUserAccount, s);
+                //.eq(User::getUserState, SystemConstants.USER_STATUS_NORMAL);
+        User user = userMapper.selectOne(queryWrapper);
+        if (Objects.isNull(user)) {
+            throw new SystemException(ResponseResult.AppHttpCodeEnum.LOGIN_ERROR);
+        }
+        LoginUserDetails loginUserDetails = new LoginUserDetails(user);
+        return loginUserDetails;
+    }
+}

+ 127 - 0
src/main/java/space/anyi/openAPI/service/impl/UserServiceImpl.java

@@ -0,0 +1,127 @@
+package space.anyi.openAPI.service.impl;
+
+
+import cn.hutool.core.util.IdUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+import space.anyi.openAPI.constant.SystemConstants;
+import space.anyi.openAPI.exception.SystemException;
+import space.anyi.openAPI.mapper.UserMapper;
+import space.anyi.openAPI.model.PageVO;
+import space.anyi.openAPI.model.ResponseResult;
+import space.anyi.openAPI.model.user.LoginUserDetails;
+import space.anyi.openAPI.model.user.User;
+import space.anyi.openAPI.model.user.UserInfo;
+import space.anyi.openAPI.model.user.dto.UserDTO;
+import space.anyi.openAPI.model.user.vo.UserVO;
+import space.anyi.openAPI.service.UserService;
+import space.anyi.openAPI.util.BeanCopyUtil;
+import space.anyi.openAPI.util.JwtUtil;
+import space.anyi.openAPI.util.RedisCache;
+
+import javax.annotation.Resource;
+import java.util.*;
+
+/**
+* @author 杨逸
+* @description 针对表【user(用户表)】的数据库操作Service实现
+* @createDate 2024-11-28 19:46:42
+*/
+@Service
+public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
+    @Resource
+    private  AuthenticationManager authenticationManager;
+    @Resource
+    private RedisCache redisCache;
+    @Resource
+    private  PasswordEncoder passwordEncoder;
+    @Override
+    public ResponseResult login(User user) {
+        //认证
+        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUserAccount(), user.getUserPassword());
+        Authentication authentication = authenticationManager.authenticate(authenticationToken);
+        if (Objects.isNull(authentication)){
+            throw new SystemException(ResponseResult.AppHttpCodeEnum.LOGIN_ERROR);
+        }
+        //生成token
+        LoginUserDetails principal = (LoginUserDetails) authentication.getPrincipal();
+        Long id = principal.getUser().getId();
+        String jwt = JwtUtil.createJWT(id.toString());
+        //todo:权限
+        //存入redis
+        redisCache.setCacheObject(SystemConstants.LOGIN_USER_REDIS_KEY+id,principal);
+        //返回结果
+        Map<String,Object> map = new HashMap<>();
+        UserInfo userInfo = new UserInfo(principal.getUser().getUserAccount(),principal.getUser().getUserName(),principal.getUser().getUserAvatar(),principal.getUser().getUserRole());
+        map.put("token",jwt);
+        map.put("userInfo",userInfo);
+        return ResponseResult.okResult(map);
+    }
+
+    @Override
+    public void addUser(UserDTO userDTO) {
+        User user = BeanCopyUtil.copyBean(userDTO, User.class);
+        //密码加密
+        user.setUserPassword(passwordEncoder.encode(user.getUserPassword()));
+        //生成ID
+        long id = IdUtil.getSnowflake(1, 1).nextId();
+        user.setId(id);
+        save(user);
+    }
+
+    @Override
+    public PageVO pageByUsernameAndUseraccount(Integer currentPage, Integer pageSize, String userName, String userAccount, String userRole) {
+        List<UserVO> userVOList = new ArrayList<>();
+        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<User>()
+                .like(StringUtils.hasText(userName), User::getUserName, userName)
+                .eq(StringUtils.hasText(userAccount), User::getUserAccount, userAccount)
+                .eq(StringUtils.hasText(userRole), User::getUserRole, userRole);
+        Page<User> page = page(new Page<User>(currentPage,pageSize), lambdaQueryWrapper);
+        for (User user : page.getRecords()) {
+            UserVO userVO = BeanCopyUtil.copyBean(user, UserVO.class);
+            userVO.setId(user.getId().toString());
+            userVOList.add(userVO);
+        }
+        return new PageVO(userVOList,page.getTotal());
+    }
+
+    @Override
+    public ResponseResult register(User user) {
+        //用户账号是否存在
+        if (userAccountExist(user.getUserAccount())){
+            throw new SystemException(ResponseResult.AppHttpCodeEnum.USERNAME_EXIST);
+        }
+        //密码加密
+        user.setUserPassword(passwordEncoder.encode(user.getUserPassword()));
+        //生成ID
+        long id = IdUtil.getSnowflake(1, 1).nextId();
+        user.setId(id);
+        //存入数据库
+        save(user);
+        return ResponseResult.okResult();
+    }
+    /**
+     * 判断用户账号是否已被注册
+     * @param userAccount
+     * @return
+     */
+    private boolean userAccountExist(String userAccount) {
+        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(User::getUserAccount,userAccount);
+        if (count(queryWrapper)>0) {
+            return true;
+        }
+        return false;
+    }
+}
+
+
+
+

+ 36 - 0
src/main/java/space/anyi/openAPI/util/BeanCopyUtil.java

@@ -0,0 +1,36 @@
+package space.anyi.openAPI.util;
+
+import org.springframework.beans.BeanUtils;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @ProjectName: BI
+ * @FileName: BeanCopyUtil
+ * @Author: 杨逸
+ * @Data:2024/11/28 20:19
+ * @Description:
+ */
+public class BeanCopyUtil {
+    private BeanCopyUtil(){}
+
+    public static <S,T> T copyBean(S source,Class<T> clazz) {
+        T target = null;
+        try {
+            target = clazz.newInstance();
+            //使用Spring的工具类实现Bean的拷贝,拷贝依靠的是Bean属性的名称
+            BeanUtils.copyProperties(source, target);
+        } catch (InstantiationException e) {
+            e.printStackTrace();
+        } catch (IllegalAccessException e) {
+            e.printStackTrace();
+        }
+        return target;
+    }
+
+    public static <S,T> List<T> copyBean(List<S> sourceList, Class<T> clazz) {
+        return sourceList.stream().map(s -> copyBean(s,clazz)).collect(Collectors.toList());
+    }
+
+}

+ 112 - 0
src/main/java/space/anyi/openAPI/util/JwtUtil.java

@@ -0,0 +1,112 @@
+package space.anyi.openAPI.util;
+
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.JwtBuilder;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import java.util.Base64;
+import java.util.Date;
+import java.util.UUID;
+
+/**
+ * @ProjectName: BI
+ * @FileName: JwtUtil
+ * @Author: 杨逸
+ * @Data:2024/11/28 20:08
+ * @Description: 
+ */
+public class JwtUtil {
+
+    //有效期为
+    public static final Long JWT_TTL = 24*60 * 60 *1000L;// 60 * 60 *1000  一个小时
+    //设置秘钥明文
+    public static final String JWT_KEY = "yangyi";
+
+    public static String getUUID(){
+        String token = UUID.randomUUID().toString().replaceAll("-", "");
+        return token;
+    }
+
+    /**
+     * 生成jtw
+     * @param subject token中要存放的数据(json格式)
+     * @return
+     */
+    public static String createJWT(String subject) {
+        JwtBuilder builder = getJwtBuilder(subject, null, getUUID());// 设置过期时间
+        return builder.compact();
+    }
+
+    /**
+     * 生成jtw
+     * @param subject token中要存放的数据(json格式)
+     * @param ttlMillis token超时时间
+     * @return
+     */
+    public static String createJWT(String subject, Long ttlMillis) {
+        JwtBuilder builder = getJwtBuilder(subject, ttlMillis, getUUID());// 设置过期时间
+        return builder.compact();
+    }
+
+    private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) {
+        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
+        SecretKey secretKey = generalKey();
+        long nowMillis = System.currentTimeMillis();
+        Date now = new Date(nowMillis);
+        if(ttlMillis==null){
+            ttlMillis=JwtUtil.JWT_TTL;
+        }
+        long expMillis = nowMillis + ttlMillis;
+        Date expDate = new Date(expMillis);
+        return Jwts.builder()
+                .setId(uuid)              //唯一的ID
+                .setSubject(subject)   // 主题  可以是JSON数据
+                .setIssuer("杨逸")     // 签发者
+                .setIssuedAt(now)      // 签发时间
+                .signWith(signatureAlgorithm, secretKey) //使用HS256对称加密算法签名, 第二个参数为秘钥
+                .setExpiration(expDate);
+    }
+
+    /**
+     * 创建token
+     * @param id
+     * @param subject
+     * @param ttlMillis
+     * @return
+     */
+    public static String createJWT(String id, String subject, Long ttlMillis) {
+        JwtBuilder builder = getJwtBuilder(subject, ttlMillis, id);// 设置过期时间
+        return builder.compact();
+    }
+
+
+
+    /**
+     * 生成加密后的秘钥 secretKey
+     * @return
+     */
+    public static SecretKey generalKey() {
+        byte[] encodedKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);
+        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
+        return key;
+    }
+
+    /**
+     * 解析
+     *
+     * @param jwt
+     * @return
+     * @throws Exception
+     */
+    public static Claims parseJWT(String jwt) throws Exception {
+        SecretKey secretKey = generalKey();
+        return Jwts.parser()
+                .setSigningKey(secretKey)
+                .parseClaimsJws(jwt)
+                .getBody();
+    }
+
+}

+ 252 - 0
src/main/java/space/anyi/openAPI/util/RedisCache.java

@@ -0,0 +1,252 @@
+package space.anyi.openAPI.util;
+
+import org.springframework.data.redis.core.BoundSetOperations;
+import org.springframework.data.redis.core.HashOperations;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @ProjectName: BI
+ * @FileName: RedisCache
+ * @Author: 杨逸
+ * @Data:2024/11/28 20:05
+ * @Description:
+ */
+@Component
+public class RedisCache {
+    @Resource
+    public RedisTemplate redisTemplate;
+
+    /**
+     * 缓存基本的对象,Integer、String、实体类等
+     *
+     * @param key 缓存的键值
+     * @param value 缓存的值
+     */
+    public <T> void setCacheObject(final String key, final T value)
+    {
+        redisTemplate.opsForValue().set(key, value);
+    }
+
+    /**
+     * 缓存基本的对象,Integer、String、实体类等
+     *
+     * @param key 缓存的键值
+     * @param value 缓存的值
+     * @param timeout 时间
+     * @param timeUnit 时间颗粒度
+     */
+    public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit)
+    {
+        redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
+    }
+
+    /**
+     * 设置有效时间
+     *
+     * @param key Redis键
+     * @param timeout 超时时间
+     * @return true=设置成功;false=设置失败
+     */
+    public boolean expire(final String key, final long timeout)
+    {
+        return expire(key, timeout, TimeUnit.SECONDS);
+    }
+
+    /**
+     * 设置有效时间
+     *
+     * @param key Redis键
+     * @param timeout 超时时间
+     * @param unit 时间单位
+     * @return true=设置成功;false=设置失败
+     */
+    public boolean expire(final String key, final long timeout, final TimeUnit unit)
+    {
+        return redisTemplate.expire(key, timeout, unit);
+    }
+
+    /**
+     * 获得缓存的基本对象。
+     *
+     * @param key 缓存键值
+     * @return 缓存键值对应的数据
+     */
+    public <T> T getCacheObject(final String key)
+    {
+        ValueOperations<String, T> operation = redisTemplate.opsForValue();
+        return operation.get(key);
+    }
+
+    /**
+     * 删除单个对象
+     *
+     * @param key
+     */
+    public boolean deleteObject(final String key)
+    {
+        return redisTemplate.delete(key);
+    }
+
+    /**
+     * 删除集合对象
+     *
+     * @param collection 多个对象
+     * @return
+     */
+    public long deleteObject(final Collection collection)
+    {
+        return redisTemplate.delete(collection);
+    }
+
+    /**
+     * 缓存List数据
+     *
+     * @param key 缓存的键值
+     * @param dataList 待缓存的List数据
+     * @return 缓存的对象
+     */
+    public <T> long setCacheList(final String key, final List<T> dataList)
+    {
+        Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
+        return count == null ? 0 : count;
+    }
+
+    /**
+     * 获得缓存的list对象
+     *
+     * @param key 缓存的键值
+     * @return 缓存键值对应的数据
+     */
+    public <T> List<T> getCacheList(final String key)
+    {
+        return redisTemplate.opsForList().range(key, 0, -1);
+    }
+
+    /**
+     * 缓存Set
+     *
+     * @param key 缓存键值
+     * @param dataSet 缓存的数据
+     * @return 缓存数据的对象
+     */
+    public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet)
+    {
+        BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
+        Iterator<T> it = dataSet.iterator();
+        while (it.hasNext())
+        {
+            setOperation.add(it.next());
+        }
+        return setOperation;
+    }
+
+    /**
+     * 获得缓存的set
+     *
+     * @param key
+     * @return
+     */
+    public <T> Set<T> getCacheSet(final String key)
+    {
+        return redisTemplate.opsForSet().members(key);
+    }
+
+    /**
+     * 缓存Map
+     *
+     * @param key
+     * @param dataMap
+     */
+    public <T> void setCacheMap(final String key, final Map<String, T> dataMap)
+    {
+        if (dataMap != null) {
+            redisTemplate.opsForHash().putAll(key, dataMap);
+        }
+    }
+
+    /**
+     * 获得缓存的Map
+     *
+     * @param key
+     * @return
+     */
+    public <T> Map<String, T> getCacheMap(final String key)
+    {
+        return redisTemplate.opsForHash().entries(key);
+    }
+
+    /**
+     * 往Hash中存入数据
+     *
+     * @param key Redis键
+     * @param hKey Hash键
+     * @param value 值
+     */
+    public <T> void setCacheMapValue(final String key, final String hKey, final T value)
+    {
+        redisTemplate.opsForHash().put(key, hKey, value);
+    }
+
+    /**
+     * 自增map中的值
+     * @param key map的key
+     * @param hKey map中的key
+     */
+    public void incrementCacheMapValue(final String key,final String hKey){
+        redisTemplate.opsForHash().increment(key,hKey,1);
+    }
+
+    /**
+     * 获取Hash中的数据
+     *
+     * @param key Redis键
+     * @param hKey Hash键
+     * @return Hash中的对象
+     */
+    public <T> T getCacheMapValue(final String key, final String hKey)
+    {
+        HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
+        return opsForHash.get(key, hKey);
+    }
+
+    /**
+     * 删除Hash中的数据
+     *
+     * @param key
+     * @param hkey
+     */
+    public void delCacheMapValue(final String key, final String hkey)
+    {
+        HashOperations hashOperations = redisTemplate.opsForHash();
+        hashOperations.delete(key, hkey);
+    }
+
+    /**
+     * 获取多个Hash中的数据
+     *
+     * @param key Redis键
+     * @param hKeys Hash键集合
+     * @return Hash对象集合
+     */
+    public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys)
+    {
+        return redisTemplate.opsForHash().multiGet(key, hKeys);
+    }
+
+    /**
+     * 获得缓存的基本对象列表
+     *
+     * @param pattern 字符串前缀
+     * @return 对象列表
+     */
+    public Collection<String> keys(final String pattern)
+    {
+        return redisTemplate.keys(pattern);
+    }
+}

+ 54 - 0
src/main/java/space/anyi/openAPI/util/SecurityUtils.java

@@ -0,0 +1,54 @@
+package space.anyi.openAPI.util;
+
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import space.anyi.openAPI.model.user.LoginUserDetails;
+
+import java.util.Objects;
+
+/**
+ * @ProjectName: BI
+ * @FileName: SecurityUtils
+ * @Author: 杨逸
+ * @Data:2024/11/28 20:42
+ * @Description:
+ */
+public class SecurityUtils {
+
+    /**
+     * 获取用户
+     **/
+    public static LoginUserDetails getLoginUser()
+    {
+        Authentication authentication = getAuthentication();
+        if (Objects.isNull(authentication)) {
+            return null;
+        }
+
+        Object principal = authentication.getPrincipal();
+        if (Objects.isNull(principal)) {
+            return null;
+        }
+        //匿名用户
+        if (principal instanceof String){
+            return null;
+        }
+        return (LoginUserDetails) principal;
+    }
+
+    /**
+     * 获取Authentication
+     */
+    public static Authentication getAuthentication() {
+        return SecurityContextHolder.getContext().getAuthentication();
+    }
+
+    public static Boolean isAdmin(){
+        String userRole = getLoginUser().getUser().getUserRole();
+        return "管理员".equals(userRole);
+    }
+
+    public static Long getUserId() {
+        return getLoginUser().getUser().getId();
+    }
+}

+ 44 - 0
src/main/java/space/anyi/openAPI/util/WebUtils.java

@@ -0,0 +1,44 @@
+package space.anyi.openAPI.util;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+
+/**
+ * @ProjectName: BI
+ * @FileName: WebUtils
+ * @Author: 杨逸
+ * @Data:2024/11/28 20:10
+ * @Description:
+ */
+public class WebUtils {
+    /**
+     * 将字符串渲染到客户端
+     *
+     * @param response 渲染对象
+     * @param string 待渲染的字符串
+     * @return null
+     */
+    public static void renderString(HttpServletResponse response, String string) {
+        try
+        {
+            response.setStatus(200);
+            response.setContentType("application/json");
+            response.setCharacterEncoding("utf-8");
+            response.getWriter().print(string);
+        }
+        catch (IOException e)
+        {
+            e.printStackTrace();
+        }
+    }
+
+
+    public static void setDownLoadHeader(String filename, HttpServletResponse response) throws UnsupportedEncodingException {
+        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
+        response.setCharacterEncoding("utf-8");
+        String fname= URLEncoder.encode(filename,"UTF-8").replaceAll("\\+", "%20");
+        response.setHeader("Content-disposition","attachment; filename="+fname);
+    }
+}

+ 26 - 0
src/main/resources/application.yaml

@@ -0,0 +1,26 @@
+server:
+  port: 8080
+spring:
+  application:
+    name: open-api-platform
+  datasource:
+    driver-class-name: com.mysql.jdbc.Driver
+    username: root
+    password: hsp
+    url: jdbc:mysql://localhost:3306/open_api_platform?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
+  redis:
+    database: 0
+    host: localhost
+    port: 6379
+  mvc:
+    pathmatch:
+      matching-strategy: ant_path_matcher
+mybatis-plus:
+  global-config:
+    db-config:
+      logic-delete-field: deleteFlag
+      logic-delete-value: 1
+      logic-not-delete-value: 0
+  configuration:
+    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
+  mapper-locations: classpath:/mapper/*.xml

+ 24 - 0
src/main/resources/mapper/UserMapper.xml

@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="space.anyi.openAPI.mapper.UserMapper">
+
+    <resultMap id="BaseResultMap" type="space.anyi.openAPI.model.user.User">
+            <id property="id" column="id" jdbcType="BIGINT"/>
+            <result property="userAccount" column="user_account" jdbcType="VARCHAR"/>
+            <result property="userPassword" column="user_password" jdbcType="VARCHAR"/>
+            <result property="userName" column="user_name" jdbcType="VARCHAR"/>
+            <result property="userAvatar" column="user_avatar" jdbcType="VARCHAR"/>
+            <result property="userRole" column="user_role" jdbcType="VARCHAR"/>
+            <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
+            <result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
+            <result property="deleteFlag" column="delete_flag" jdbcType="TINYINT"/>
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        id,user_account,user_password,
+        user_name,user_avatar,user_role,
+        create_time,update_time,delete_flag
+    </sql>
+</mapper>