从0开发简单的权限管理系统

创建springboot项目

配置环境

  • JDK1.8

  • maven版本为3.6.1

  • mysql5.7

  • redis6.2.7

后端结构

├─db #项目初始化SQL脚本
├─src
│  ├─main 
│  │  ├─java
│  │  │  ├─com.···.···
│  │  │  │  ├─common #通用包
│  │  │  │  │  ├─aop #切面管理,用于获取日志和权限控制
│  │  │  │  │  ├─config #配置管理
│  │  │  │  │  ├─constant #常量管理
│  │  │  │  │  ├─data #公共数据管理
│  │  │  │  │  ├─exception #全局异常处理
│  │  │  │  │  ├─utils #工具类管理
│  │  │  │  ├─controller #控制层
│  │  │  │  ├─entity #实体类
│  │  │  │  ├─mapper #dao层
│  │  │  │  ├─service #服务层
│  │  │  │  ├─···Application #启动类(入口)
│  │  │  ├─resource #资源
│  ├─test #测试 
├─pom #依赖配置  

数据库导入

讲一下代码保存为可执行sql文件,通过idea自带或者其他工具导入数据库

/*
Navicat MySQL Data Transfer
​
Source Server         : 175.178.78.181
Source Server Version : 50740
Source Host           : 175.178.78.181:3306
Source Database       : travel
​
Target Server Type    : MYSQL
Target Server Version : 50740
File Encoding         : 65001
​
Date: 2024-02-02 21:38:16
*/
​
SET FOREIGN_KEY_CHECKS=0;
​
-- ----------------------------
-- Table structure for file
-- ----------------------------
DROP TABLE IF EXISTS `file`;
CREATE TABLE `file` (
  `id` varchar(225) NOT NULL COMMENT '唯一id',
  `url` varchar(225) NOT NULL COMMENT '文件地址',
  `name` varchar(50) NOT NULL COMMENT '文件名',
  `type` varchar(100) NOT NULL COMMENT '文件类型',
  `create_by` varchar(50) NOT NULL COMMENT '创建者',
  `if_private` int(11) NOT NULL DEFAULT '0' COMMENT '是否私有(0不私有,1私有)',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文件表';
​
DROP TABLE IF EXISTS `permission`;
CREATE TABLE `permission` (
  `id` bigint(20) NOT NULL COMMENT '唯一性id',
  `description` varchar(225) DEFAULT NULL COMMENT '权限描述',
  `expression` varchar(225) NOT NULL COMMENT '权限表达式',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
​
-- ----------------------------
-- Records of permission
-- ----------------------------
INSERT INTO `permission` VALUES ('1', '添加权限', 'ADD_PERMISSION');
INSERT INTO `permission` VALUES ('2', '删除权限', 'DELETE_PERMISSION');
INSERT INTO `permission` VALUES ('3', '修改权限', 'UPDATE_PERMISSION');
INSERT INTO `permission` VALUES ('4', '查询权限', 'READ_PERMISSION');
​
-- ----------------------------
-- Table structure for role
-- ----------------------------
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '唯一id',
  `name` varchar(50) NOT NULL COMMENT '角色名',
  `description` varchar(225) DEFAULT NULL COMMENT '角色描述',
  `permission_ids` varchar(225) DEFAULT NULL COMMENT '权限ids',
  PRIMARY KEY (`id`),
  UNIQUE KEY `role_pk` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=690 DEFAULT CHARSET=utf8mb4 COMMENT='角色表';
​
-- ----------------------------
-- Records of role
-- ----------------------------
INSERT INTO `role` VALUES ('1', 'superAdmin', '超级管理员', '1,2,3,4');
INSERT INTO `role` VALUES ('2', 'admin', '管理员', '3,4');
INSERT INTO `role` VALUES ('3', 'user', '用户', '1,2,3,4');
​
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` varchar(20) NOT NULL COMMENT '唯一id',
  `account` varchar(20) NOT NULL COMMENT '账号',
  `phone` varchar(11) DEFAULT NULL COMMENT '电话',
  `email` varchar(30) DEFAULT NULL COMMENT '邮箱',
  `password` varchar(20) NOT NULL COMMENT '密码',
  `gender` smallint(6) DEFAULT NULL COMMENT '性别(男性为0女性为1)',
  `age` int(11) DEFAULT NULL,
  `birth` date DEFAULT NULL COMMENT '出生日期',
  `role_id` int(11) DEFAULT NULL COMMENT '角色表id',
  `status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '是否启用(1为启用,0为不启用)',
  `create_date` date NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `user_pk_account` (`account`),
  UNIQUE KEY `user_pk_phone` (`phone`),
  UNIQUE KEY `user_pk_email` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
​
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', 'superAdmin', '15912365485', '11598524568@qq.com', '123456', '0', '20', '2023-12-30', '1', '1', '2023-12-30');

依赖配置

在pom.xml中cv进一下配置

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.travel.term</groupId>
    <artifactId>travel-system</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>travel-system</name>
    <description>travel-system</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <!-- fastjson工具类 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.79</version>
        </dependency>
        <!-- boot 基本依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
​
        <!--AOP-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <!--Lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!-- 数据库连接池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.15</version>
        </dependency>
        <!-- MybatisPlus -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.2</version>
        </dependency>
​
        <!-- Mysql -->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <version>8.0.31</version>
        </dependency>
​
        <!-- Hutool -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.10</version>
        </dependency>
​
        <!-- Redis-->
        <dependency>
            <groupId>org.springframework.integration</groupId>
            <artifactId>spring-integration-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!-- Redis扩展-->
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-boot-starter</artifactId>
            <version>3.18.0</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
        <!--springdoc 官方Starter-->
        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-ui</artifactId>
            <version>1.6.6</version>
        </dependency>
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.4.6</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        <!-- 图片识别Tesseract OCR -->
        <dependency>
            <groupId>net.sourceforge.tess4j</groupId>
            <artifactId>tess4j</artifactId>
            <version>4.5.4</version>
        </dependency>
    </dependencies>
​
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
​
</project>
​

代码编写(本代码的包导入无写入,根据自己的项目包路径导入即可,idea快捷键导入)

yml

server:
  port: 8848
  servlet:
    context-path: /   #根路径地址
  tomcat:
    uri-encoding: UTF-8 # Tomcat编码
    threads:
      max: 1000     # 线程池最大线程数
      min-spare: 30   #最小空闲线程数量
    max-swallow-size: -1  #表示没限制最大请求体大小
  shutdown: graceful    # 关闭服务器时:先等待正在处理的请求完成再关闭
​
​
spring:
  # 数据库
  datasource:
    url: jdbc:mysql://localhost:3306/travel?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
    username: root
    password: Tpassword
    type: com.alibaba.druid.pool.DruidDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    druid:
      filter:
        wall:
          config:
            multi-statement-allow: true   #允许执行多条SQL语句
    hikari:
      max-lifetime: 60000     # 连接的最大生命周期(ms)
      maximum-pool-size: 1000 # 连接池的最大连接数
  # redis
  redis:
    host: localhost
    database: 0
    port: 6379
    timeout: 3S
    password: password
​
  # 文件上传配置
  ## MULTIPART (MultipartProperties)
  # 开启 multipart 上传功能
  servlet:
    multipart:
      enabled: true
      # 文件写入磁盘的阈值
      file-size-threshold: 2KB
      # 最大文件大小
      max-file-size: 200MB
      # 最大请求大小
      max-request-size: 215MB
  # 文件存储所需参数
  # 所有通过 REST API 上传的文件都将存储在此目录下
  upload:
    path: C:/travel
​
  #返回json的全局时间格式
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8
​
# mybatisplus 配置
mybatis-plus:
  # Mybatis-Plus逻辑删除
  global-config:
    db-config:
      logic-delete-value: 1
      logic-not-delete-value: 0
  mapper-locations: classpath*:mapper/*.xml   # mybatis xml文件位置
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
​
logging:
  level: # 设置日志级别
    root: info
  file:
    path: logs
  logback:
    rollingpolicy: #日志滚动策略
      max-history: 2000   #最大历史文件数量
      max-file-size: 5MB    #单个日志文件最大大小
​
#分页设置
pagehelper:
  helperDialect: mysql
  reasonable: true
  supportMethodsArguments: true
  pageSizeZero: false #pageSize=0 返回所有
  params: count=countSql
​
​
​
​
# 密钥
encrypt:
  #  密钥
  key: 510463728
​
# 接口api
apis:
  # api放行白名单
  paths:
    whites:
      - /authorization/**
    #swaggerapi路径配置
    business:
      - /authorization/**
​
# 上传下载配置
upload-download:
  multipart:
    # 文件上传的最大值
    max-file-size: 512MB
    # 文件请求的最大值
    max-request-size: 512MB
    # 文件存储路径
    location: C:/travel
​

common通用层

aop:

MyInterceptor类

拦截请求并打印请求信息,同时设置请求拦截除非白名单中有该请求路径否则不放行,具体可见代码:

import com.travel.term.common.data.properties.PathsProperties;
import com.travel.term.common.data.resultAndReq.Result;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.util.AntPathMatcher;
​
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.UUID;
/**
 * AOP 类
 */
@Aspect
@Component
@Slf4j
public class MyInterceptor {
​
    @Resource
    private PathsProperties pathsProperties;
​
    private final AntPathMatcher pathMatcher = new AntPathMatcher();
​
    /**
     * 拦截所有请求,打印请求信息
     */
    @Around("execution(* com.travel.term.controller.*.*(..))")
    public Object doLogInterceptor(ProceedingJoinPoint point) throws Throwable {
        // 计时
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        // 获取请求路径
        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
        HttpServletRequest httpServletRequest = ((ServletRequestAttributes) requestAttributes).getRequest();
        // 生成请求唯一 id
        String requestId = UUID.randomUUID().toString();
        String url = httpServletRequest.getRequestURI();
        // 获取请求参数
        Object[] args = point.getArgs();
        String reqParam = "[" + StringUtils.join(args, ", ") + "]";
        // 输出请求日志
        log.info("request start,id: {}, path: {}, ip: {}, params: {}", requestId, url,
                httpServletRequest.getRemoteHost(), reqParam);
        // 执行原方法
        Object result = point.proceed();
        // 输出响应日志
        stopWatch.stop();
        long totalTimeMillis = stopWatch.getTotalTimeMillis();
        log.info("request end, id: {}, cost: {}ms", requestId, totalTimeMillis);
        return result;
    }
​
    /**
     * 权限控制
     *
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("execution(* com.travel.term.controller.*.*(..))")
    public Object doPermissionInterceptor(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取请求头信息
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String uri = request.getRequestURI().toString();
        String actualHeaderValue = request.getHeader("token");
        // 有token放行,没有token不得访问,除白名单外
        if (actualHeaderValue != null && !actualHeaderValue.isEmpty()) {
            //执行原方法
            return joinPoint.proceed();
        } else {
            // 判断是否为白名单路径,是则放行,否则拦截
            for (String white : pathsProperties.getWhites()) {
                if (pathMatcher.match(white, uri)) {
                    return joinPoint.proceed();
                }
            }
            return Result.fail("无操作权限!!");
        }
    }
}
PermissionAspect类

注解拦截判断是否能够执行被注解标注的方法,具体见代码:

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.travel.term.common.exception.CommonException;
import com.travel.term.common.utils.StringUtils;
import com.travel.term.entity.Permission;
import com.travel.term.entity.Role;
import com.travel.term.entity.User;
import com.travel.term.service.PermissionService;
import com.travel.term.service.RoleService;
import com.travel.term.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
​
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.List;
import java.util.stream.Collectors;
​
@Aspect
@Component
@Slf4j
public class PermissionAspect {
​
    @Resource
    private UserService userService;
​
    @Resource
    private RoleService roleService;
​
    @Resource
    private PermissionService permissionService;
​
    /**
     * 目标方法
     */
    @Pointcut("@annotation(com.travel.term.common.aop.RequestPermission)")
    private void permission() {
    }
​
    /**
     * 目标方法调用之前执行
     */
    @Before("permission()")
    public void doBefore() {
        System.out.println("================== step 2: before ==================");
    }
​
    /**
     * 目标方法调用之后执行
     */
    @After("permission()")
    public void doAfter() {
        System.out.println("================== step 4: after ==================");
    }
​
    /**
     * 每次请求接口进行权限校验
     *
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("permission()")
    public Object doPermissionInterceptor(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取请求头信息
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
​
        String actualHeaderValue = request.getHeader("token");
        // 对token进行判断
        if (actualHeaderValue == null) {
            throw new CommonException("您没有访问权限或者没有登录!");
        }
        if (actualHeaderValue.contains("superAdmin")) {
            // 超管,放行
            return joinPoint.proceed();
        } else {
            // 不是超管,进行权限验证
            //token切割
            String[] role = actualHeaderValue.split("-");
            //获取token中的用户id
            String id = role[role.length - 1];
            String permission = role[role.length - 2];
            return checkPermission(joinPoint, id, permission);
        }
    }
​
    private Object checkPermission(ProceedingJoinPoint joinPoint, String id, String use) throws Throwable {
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        RequestPermission permission = method.getAnnotation(RequestPermission.class);
        String name = permission.name();
        // 查询权限列表
        LambdaQueryWrapper<Permission> queryWrapper = new LambdaQueryWrapper<>();
        //查询所有权限
        User user = userService.getById(id);
        Role role;
        if (StringUtils.nullOrEmpty(user) || StringUtils.nullOrEmpty(role = (roleService.getById(user.getRoleId())))) {
            throw new CommonException("账号异常,请联系管理员");
        }
        //切割获取ids
        String[] roleIds = role.getPermissionIds().split(",");
        //查询
        queryWrapper.in(Permission::getId, roleIds);
        List<Permission> list = permissionService.list(queryWrapper);
        List<String> collect = list.stream().map((expression) -> expression.getExpression()).collect(Collectors.toList());
        System.out.println(collect);
        // 判断
        if (!collect.contains(name) && (collect.stream().filter(item -> (use + ":" + item).equals(name))).collect(Collectors.toList()).size() == 0) {
            throw new CommonException("您没有权限操作");
        }
        return joinPoint.proceed();
    }
​
}
RequestPermission注解

自定义权限控制注解,注解方法为以上PermissionAspect类中方法,可自行修改,本例写的比较简单,可根据项目需要修改编写:

import com.travel.term.common.constant.PermissionConstant;
​
import java.lang.annotation.*;
​
​
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented     // 在生成javac时显示该注解的信息
public @interface RequestPermission {
    //设置一个权限名称,默认为读权限
    String name() default PermissionConstant.READ;
}

config

CorsConfig类

用于设置资源共享

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
​
​
/**
 * 全局跨域配置
 */
@Configuration
public class CorsConfig implements WebMvcConfigurer {
​
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        // 覆盖所有请求
        registry.addMapping("/**")
                // 允许发送 Cookie
                .allowCredentials(true)
                // 放行哪些域名(必须用 patterns,否则 * 会和 allowCredentials 冲突)
                .allowedOriginPatterns("*")
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .allowedHeaders("*")
                .exposedHeaders("*");
    }
​
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/api/file/**").addResourceLocations("file:" + "C:/travel");
    }
​
}
MyBatisPlusConfig类

mybatisplus配置类

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;

/**
 * MyBatis Plus 配置

 */
@Configuration
@MapperScan("com.travel.term.mapper")
public class MyBatisPlusConfig {

    /**
     * 拦截器配置
     *
     * @return
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}
RedisConfig类:

redis配置类

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        return template;
    }
}
SpringDocConfig类

api文档(swagger配置)

/**
 * SpringDoc API文档相关配置
 * Created by macro on 2022/3/4.
 */
@Configuration
@Slf4j
public class SpringDocConfig {

    @Resource
    private PathsProperties pathsProperties;

    @Bean
    public OpenAPI mallTinyOpenAPI() {
        return new OpenAPI()
                .info(new Info().title("旅游管理")
                        .description("SpringDoc API 演示")
                        .version("v1.0.0")
                        .license(new License().name("Apache 2.0").url("")))
                .externalDocs(new ExternalDocumentation()
                        .description("travel")
                        .url(""))
                .schemaRequirement("Authorization", this.securityScheme());

    }


    private SecurityScheme securityScheme() {
        SecurityScheme securityScheme = new SecurityScheme();
        //类型
        securityScheme.setType(SecurityScheme.Type.APIKEY);
        //请求头的name
        securityScheme.setName("token");
        //token所在未知
        securityScheme.setIn(SecurityScheme.In.HEADER);
        return securityScheme;
    }

    /**
     * 用户管理
     *
     * @return
     */
    @Bean
    public GroupedOpenApi userApi() {
        return GroupedOpenApi.builder()
                .group("user用户管理API")
                .pathsToMatch("/user/**", "/role/**", "/permission/**")
                .build();
    }

    /**
     * 业务管理
     *
     * @return
     */
    @Bean
    public GroupedOpenApi CrudApi() {
        return GroupedOpenApi.builder()
                .group("旅游管理接口")
                .pathsToMatch(StringUtils.listToArray(pathsProperties.getBusiness()))
                .build();
    }

}

constant

Constants类:

用于返回数据时的code

public class Constants {
    public static final int SUCCESS = 200;
    public static final int FAIL = 500;
}
DefaultErrorResultConstant类

异常代码:

import com.travel.term.common.data.handle.ErrorResult;

public class DefaultErrorResultConstant {

    public static final ErrorResult SYSTEM_ERROR = new ErrorResult("500", "系统异常");
    public static final ErrorResult CUSTOM_ERROR = new ErrorResult("C99999", "自定义异常");
    public static final ErrorResult MYBATIS_PLUS_ERROR = new ErrorResult("S00008", "数据库操作业务异常");
    public static final ErrorResult NUMBER_FORMAT_ERROR = new ErrorResult("S00009", "数字转化异常");
    public static final ErrorResult HTTP_ERROR = new ErrorResult("S00009", "请求异常,请检查");
    public static final ErrorResult NULL_POINT = new ErrorResult("S00010", "空指针异常,请检查");
}
PermissionConstant类

权限常量,对应数据库

public class PermissionConstant {
    /**
     * 查看权限
     */
    public final static String READ = "READ_PERMISSION";
    /**
     * 添加权限
     */
    public final static String ADD = "ADD_PERMISSION";
    /**
     * 修改权限
     */
    public final static String DELETE = "DELETE_PERMISSION";
    /**
     * 删除权限
     */
    public final static String UPDATE = "UPDATE_PERMISSION";
}
RoleConstant类
public class RoleConstant {
    public static final Integer 超管 = 1;
    public static final Integer 管理员 = 2;
    public static final Integer 用户 = 3;
}

data

handle.ErrorResult:

异常数据,,包含错误码和报错消息,用于代码报错或者返回失败结果时使用

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ErrorResult implements Serializable {

    private static final long serialVersionUID = -8738363760223125457L;

    /**
     * 错误码
     */
    private String code;

    /**
     * 错误消息
     */
    private String msg;
  
    public static ErrorResult build(ErrorResult commonErrorResult, String msg) {
        return new ErrorResult(commonErrorResult.getCode(), commonErrorResult.getMsg() + " " + msg);
    }
}
properties.FileProperties

读取配置文件中有关文件存储的数据

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@Configuration
@ConfigurationProperties(prefix = "upload-download.multipart")
@Data
public class FileProperties {
    private String maxFileSize;
    private String maxRequestSize;
    private String location;
}
properties.PathsProperties

读取配置文件中有关路径(swagger路径和白名单数据)的数据

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.List;

/**
 * @author: cai
 * @description: api配置路径
 * @date: 2023/12/11
 */
@Configuration
@ConfigurationProperties(prefix = "apis.paths")
@Data
public class PathsProperties {
    //白名单
    private List<String> whites = new ArrayList<>();
    // 业务接口
    private List<String> business = new ArrayList<>();
}
resultAndReq.PageResult

分页结果返回对象

import com.github.pagehelper.PageInfo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

import java.io.Serializable;
import java.util.List;

@Data
@Schema(name="PageResult",description ="分页结果" )
public class PageResult<T> implements Serializable {

    @Schema(name="pageNum",description ="第几页" )
    private int pageNum;
    @Schema(name="pageSize",description ="每页条数" )
    private int pageSize;
    @Schema(name="pages",description ="总页数" )
    private int pages;
    @Schema(name="total",description ="总条数" )
    private long total;
    @Schema(name="records",description ="数据结果" )
    private List<T> records;

    public PageResult() {

    }

    /**
     * 通过pageHelper中的pageInfo进行包装
     *
     * @param list
     */
    public PageResult(List<T> list) {
        PageInfo pageInfo = new PageInfo<>(list);
        this.setRecords(pageInfo.getList());
        this.setPageNum(pageInfo.getPageNum());
        this.setPageSize(pageInfo.getPageSize());
        this.setPages(pageInfo.getPages());
        this.setTotal(pageInfo.getTotal());
    }

    /**
     * 外部计算直接包装分页
     *
     * @param list
     * @param pageNum
     * @param pageSize
     * @param total
     */
    public PageResult(List<T> list, int pageNum, int pageSize, long total) {
        int pages = (int) (total / pageSize);
        pages = total % pageSize != 0 ? pages + 1 : pages;
        this.setRecords(list);
        this.setPageNum(pageNum);
        this.setPageSize(pageSize);
        this.setPages(pages);
        this.setTotal(total);
    }
}
resultAndReq.ReqPage:

分页接口接收分页数据对象类

import java.io.Serializable;

public class ReqPage implements Serializable {
    private Integer pageNum = 1;
    private Integer pageSize = 10;

    public Integer getPageNum() {
        return pageNum;
    }

    public ReqPage setPageNum(Integer pageNum) {
        if (pageNum == null) {
            return this;
        }
        this.pageNum = pageNum;
        return this;
    }

    public Integer getPageSize() {
        return pageSize;
    }

    public ReqPage setPageSize(Integer pageSize) {
        if (pageNum == null) {
            return this;
        }
        this.pageSize = pageSize;
        return this;
    }
}
resultAndReq.Result

非分页接口数据返回对象类

import com.travel.term.common.constant.Constants;
import lombok.Data;
import lombok.experimental.Accessors;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

@Accessors(chain = true)
@Data
public class Result<T> implements Serializable {

    private static final long serialVersionUID = 1L;
    private boolean success = true;
    private int code = Constants.SUCCESS;
    private String msg;
    private T data;
    private Map<String, String> param = new HashMap<>();

    public static <T> Result<T> buildResult(T data, int code, String msg) {
        return new Result<T>().setCode(code).setData(data).setMsg(msg).setSuccess(code == Constants.SUCCESS ? true : false);
    }

    public static <T> Result<T> success() {
        return buildResult(null, Constants.SUCCESS, null);
    }

    public static <T> Result<T> success(String msg) {
        return buildResult(null, Constants.SUCCESS, msg);
    }

    public static <T> Result<T> success(T data) {
        return buildResult(data, Constants.SUCCESS, null);
    }

    public static <T> Result<T> success(T data, String msg) {
        return buildResult(data, Constants.SUCCESS, msg);
    }

    public static <T> Result<T> fail() {
        return buildResult(null, Constants.FAIL, null);
    }

    public static <T> Result<T> fail(String msg) {
        return buildResult(null, Constants.FAIL, msg);
    }

    public static <T> Result<T> fail(T data) {
        return buildResult(data, Constants.FAIL, null);
    }

    public static <T> Result<T> fail(T data, String msg) {
        return buildResult(data, Constants.FAIL, msg);
    }

    public static <T> Result<T> fail(int code, String msg) {
        return buildResult(null, code, msg);
    }

}
exception.CommonException

自定义异常

import com.travel.term.common.data.handle.ErrorResult;
import lombok.Data;
import lombok.EqualsAndHashCode;

@EqualsAndHashCode(callSuper = true)
@Data
public class CommonException extends RuntimeException {

    protected ErrorResult errorResult;

    public CommonException(String message) {
        super(message);
    }

    public CommonException(String message, Throwable cause) {
        super(message, cause);
    }

    public CommonException(Throwable cause) {
        super(cause);
    }

    protected CommonException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }

    public CommonException(String code, String msg) {
        super(msg + "(" + code + ")");
        this.errorResult = new ErrorResult(code, msg);
    }

    public CommonException(ErrorResult errorResult) {
        super(errorResult.getMsg() + "(" + errorResult.getCode() + ")");
        this.errorResult = errorResult;
    }
}
exception.GlobalExceptionHandler

全局异常处理

import cn.hutool.http.HttpException;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.travel.term.common.constant.DefaultErrorResultConstant;
import com.travel.term.common.data.handle.ErrorResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 通用业务异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = CommonException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ErrorResult handleCommonException(CommonException e) {
        log.error("{}, {}", e.getMessage(), e);
        if (e.getErrorResult() != null) {
            return e.getErrorResult();
        }
        return new ErrorResult(DefaultErrorResultConstant.CUSTOM_ERROR.getCode(), e.getMessage());
    }

    /**
     * 其他运行时异常
     * @param e
     * @return
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ErrorResult handleDefaultException(Exception e) {
        log.error("{}, {}", e.getMessage(), e);
        return DefaultErrorResultConstant.SYSTEM_ERROR;
    }

    /**
     * 其mybatis-plus异常
     * @param e
     * @return
     */
    @ExceptionHandler(value = MybatisPlusException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ErrorResult handleMybatisException(Exception e) {
        log.error("{}, {}", e.getMessage(), e);
        return DefaultErrorResultConstant.MYBATIS_PLUS_ERROR;
    }

    /**
     * 数字格式化异常
     * @param e
     * @return
     */
    @ExceptionHandler(value = NumberFormatException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ErrorResult handleNumberException(Exception e) {
        log.error("{}, {}", e.getMessage(), e);
        return DefaultErrorResultConstant.NUMBER_FORMAT_ERROR;
    }

    @ExceptionHandler(value = HttpException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ErrorResult handleHttpException(Exception e) {
        log.error("{}, {}", e.getMessage(), e);
        return DefaultErrorResultConstant.HTTP_ERROR;
    }

    @ExceptionHandler(value = NullPointerException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ErrorResult handleNullPointerException(Exception e) {
        log.error("{}, {}", e.getMessage(), e);
        return DefaultErrorResultConstant.NULL_POINT;
    }
}

utils

EncryptUtils工具类

密码加密和解密

import com.travel.term.common.exception.CommonException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

@Configuration
public class EncryptUtils {
    private static Integer key;

    @Value("${encrypt.key}")
    public void setKey(Integer key) {
        EncryptUtils.key = key;
    }

    /**
     * 解密
     *
     * @param str
     */
    public static String decrypt(String str) {
        if (StringUtils.nullOrEmpty(str)){
            throw new CommonException("没有设置密码或者密码为空!");
        }
        //解密
        int k = Integer.parseInt("-" + key);
        String content = "";
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if (c >= 'a' && c <= 'z')//如果字符串中的某个字符是小写字母
            {
                c += k % 26;//移动key%26位
                if (c < 'a')
                    c += 26;//向左超界
                if (c > 'z')
                    c -= 26;//向右超界
            } else if (c >= 'A' && c <= 'Z')//如果字符串中的某个字符是大写字母
            {
                c += k % 26;//移动key%26位
                if (c < 'A')
                    c += 26;//向左超界
                if (c > 'Z')
                    c -= 26;//向右超界
            }
            content += c;//将解密后的字符连成字符串
        }
        return content;
    }

    /**
     * 加密
     *
     * @param str
     */
    public static String kaisaEncrypt(String str) {
        //加密
        String encryptResult = "";
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if (c >= 'a' && c <= 'z')//如果字符串中的某个字符是小写字母
            {
                c += key % 26;//移动key%26位
                if (c < 'a')
                    c += 26;//向左超界
                if (c > 'z')
                    c -= 26;//向右超界
            } else if (c >= 'A' && c <= 'Z')//如果字符串中的某个字符是大写字母
            {
                c += key % 26;//移动key%26位
                if (c < 'A')
                    c += 26;//向左超界
                if (c > 'Z')
                    c -= 26;//向右超界
            }
            encryptResult += c;//将加密后的字符连成字符串
        }
        return encryptResult;
    }

}
FileUtils

文件操作工具类

import java.io.File;

public class FileUtils {

    public static boolean deleteFile(String path) {
        File file = new File(path);
        if (!file.exists()) {
            return false;
        }
        return file.delete();
    }
}
StringUtils

字符串工具类

import java.util.List;

public class StringUtils {

    /**
     * 将集合转为数组
     */
    public static String[] listToArray(List<String> list) {
        String[] result = new String[list.size()];
        for (int i = 0; i < list.size(); i++) {
            result[i] = list.get(i);
        }
        return result;
    }

    public static Boolean nullOrEmpty(String... args) {
        for (String arg : args) {
            if (arg == "" || arg == null) {
                return true;
            }
        }
        return false;
    }

    public static Boolean nullOrEmpty(Object o) {
        return o == null ? true : o instanceof String ? ((String) o).isEmpty() : false;
    }
}

controller层

其中的OrcController为图片识别,不在这里写出,需要可到我主页的文章中寻找(,TourismController为我本项目的接口,不在这里写出)

Authorization

登录接口

import cn.hutool.core.lang.UUID;
import com.travel.term.common.exception.CommonException;
import com.travel.term.common.data.resultAndReq.Result;
import com.travel.term.common.utils.StringUtils;
import com.travel.term.entity.Role;
import com.travel.term.entity.User;
import com.travel.term.entity.req.ReqLoginUser;
import com.travel.term.service.RoleService;
import com.travel.term.service.UserService;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

@RestController
@RequestMapping("/authorization")
@Tag(name = "登录接口", description = "登录接口信息数据,包括获取token")
@Slf4j
public class Authorization {

    @Resource
    private UserService userService;

    @Resource
    private RoleService roleService;

    @GetMapping("/login")
    public Result<String> login(ReqLoginUser loginUserVo) {
        //检查账号密码是否存在并正确
        User user = userService.checkUserInfo(loginUserVo);
        if (!StringUtils.nullOrEmpty(user)) {
            if (user.getId().equals("-1")) {
                return Result.fail("没有该账号");
            }
            if (user.getStatus() == 0) {
                return Result.fail("该账号已被禁用,请联系管理员!");
            }
            return Result.success(user.getId(), "登录成功!");
        }
        return Result.fail("账号或密码错误!");
    }

    @GetMapping("/token/{id}")
    public Result<String> buildToken(@PathVariable("id") String id) {
        // id解密
//        String newId = EncryptUtils.decrypt(id);
        // 获取角色
        log.info(id);
        User user = userService.getById(id);
        log.info(user.toString());
        if (StringUtils.nullOrEmpty(user)) {
            throw new CommonException("账号异常,请联系管理员");
        }
        // 账号检测通过,获取角色
        Role role = roleService.getById(user.getRoleId());
        String token = buildToken(role.getName(), user.getId());
        return Result.success(token, "获取token为" + token);
    }

    private String buildToken(String role, String id) {
        // uuid和角色名称和用户id组成token
        return UUID.randomUUID() + "-" + role + "-" + id;
    }
}

IFileController

文件接口,操作文件

import com.github.pagehelper.PageHelper;
import com.travel.term.common.aop.RequestPermission;
import com.travel.term.common.constant.PermissionConstant;
import com.travel.term.common.data.resultAndReq.PageResult;
import com.travel.term.common.data.resultAndReq.ReqPage;
import com.travel.term.common.data.resultAndReq.Result;
import com.travel.term.common.utils.StringUtils;
import com.travel.term.entity.IFile;
import com.travel.term.entity.req.ReqIFile;
import com.travel.term.service.IFileService;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.Calendar;
import java.util.Date;
import java.util.UUID;

@RestController
@Tag(name = "文件接口", description = "文件操作接口")
@RequestMapping("/file")
public class IFileController {
    @Resource
    private IFileService iFileService;

    @GetMapping
    @RequestPermission(name = ("admin:" + PermissionConstant.READ))
    public Result<PageResult<IFile>> pageList(ReqPage reqPage, ReqIFile reqIFile) {
        PageHelper.startPage(reqPage.getPageNum(), reqPage.getPageSize());
        return Result.success(iFileService.list(reqIFile), "查询成功");
    }


    @PostMapping("/upload")
    public Result<IFile> uploadFile(ReqIFile reqIFile, MultipartFile multipartFiles) {
        File fileDir = iFileService.checkAddr();
        IFile iFile = new IFile();
        try {
            if (!StringUtils.nullOrEmpty(multipartFiles)) {
                // 创建时间作为路径
                Date currentDate = new Date();
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(currentDate);

                int year = calendar.get(Calendar.YEAR);
                int month = calendar.get(Calendar.MONTH) + 1;
                int day = calendar.get(Calendar.DAY_OF_MONTH);
                String uuid = UUID.randomUUID().toString().replaceAll("-", "");
                // 保存
                try {
                    //以原来的名称命名,覆盖掉旧的,这里也可以使用UUID之类的方式命名,这里就没有处理了
                    String storagePath = fileDir.getAbsolutePath() + "/" + year + "/" + month + "/" + day + "/" + uuid + multipartFiles.getOriginalFilename().substring(multipartFiles.getOriginalFilename().lastIndexOf("."));
                    File file = new File(storagePath);
                    if (!file.exists() && !file.isDirectory()) {
                        file.mkdirs();
                    }
                    System.out.println("上传的文件:" + multipartFiles.getName() + "," + multipartFiles.getContentType() + "," + multipartFiles.getOriginalFilename()
                            + ",保存的路径为:" + storagePath);
                    // 3种方法: 第1种
//                        Streams.copy(multipartFiles[i].getInputStream(), new FileOutputStream(storagePath), true);
                    // 第2种
//                    Path path = Paths.get(storagePath);
//                    Files.write(path, multipartFiles[i].getBytes());
                    // 第3种
                    multipartFiles.transferTo(file);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                // 上传成功,保存文件信息
                iFile.setId(uuid)
                        .setUrl("/" + year + "/" + month + "/" + day + "/" + uuid + multipartFiles.getOriginalFilename().substring(multipartFiles.getOriginalFilename().lastIndexOf(".")))
                        .setName(uuid + multipartFiles.getOriginalFilename().substring(multipartFiles.getOriginalFilename().lastIndexOf(".")))
                        .setType(multipartFiles.getContentType())
                        .setIfPrivate(Integer.parseInt(reqIFile.getIfPrivate()))
                        .setCreateBy(reqIFile.getCreateBy());
                if (!iFileService.save(iFile)) {
                    return Result.fail("上传失败!");
                }
            }
        } catch (Exception e) {
            return Result.fail(e.getMessage());
        }
        //前端可以通过状态码,判断文件是否上传成功
        return Result.success(iFile, "上传成功");
    }

    /**
     * @param id       文件标识
     * @param response
     * @return
     */
    @GetMapping("/download")
    public Result<IFile> downloadFile(@RequestParam String id, HttpServletResponse response) {
        // 查询是否存在该文件
        IFile iFile = iFileService.getById(id);
        if (StringUtils.nullOrEmpty(iFile)) {
            return Result.fail("没有该文件");
        }
        File fileDir = iFileService.checkAddr();
        // 文件下载操作
        OutputStream os = null;
        InputStream is = null;
        try {
            // 取得输出流
            os = response.getOutputStream();
            // 清空输出流
            response.reset();
            response.setContentType("application/x-download;charset=utf-8");
            //Content-Disposition中指定的类型是文件的扩展名,并且弹出的下载对话框中的文件类型图片是按照文件的扩展名显示的,点保存后,文件以filename的值命名,
            // 保存类型以Content中设置的为准。注意:在设置Content-Disposition头字段之前,一定要设置Content-Type头字段。
            //把文件名按UTF-8取出,并按ISO8859-1编码,保证弹出窗口中的文件名中文不乱码,中文不要太多,最多支持17个中文,因为header有150个字节限制。
            response.setHeader("Content-Disposition", "attachment;filename=" + new String(iFile.getName().getBytes("utf-8"), "ISO8859-1"));
            //读取流
            File f = new File(fileDir.getAbsolutePath() + iFile.getUrl());
            is = new FileInputStream(f);
            if (is == null) {
                System.out.println("下载附件失败,请检查文件“" + iFile.getUrl() + "”是否存在");
                return Result.fail("下载附件失败,请检查文件“" + iFile.getUrl() + "”是否存在");
            }
            //复制
            IOUtils.copy(is, response.getOutputStream());
            response.getOutputStream().flush();
        } catch (IOException e) {
            return Result.fail("下载附件失败,error:" + e.getMessage());
        }
        //文件的关闭放在finally中
        finally {
            try {
                if (is != null) {
                    is.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (os != null) {
                    os.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //其实,这个返回什么都不重要
        return Result.success(iFile, "下载成功");
    }

    @DeleteMapping("/{id}")
    @RequestPermission(name = (PermissionConstant.DELETE))
    public Result<Boolean> deleteFile(@PathVariable("id") String id) {
        if (StringUtils.nullOrEmpty(id)) {
            return Result.fail(false, "请注意选择要删除的文件");
        }
        IFile file = iFileService.getById(id);
        String path = iFileService.checkAddr().getAbsolutePath() + (StringUtils.nullOrEmpty(file) ? "" : file.getUrl());
        return iFileService.deleteFileByPath(file, path) ? Result.success(true, "删除成功") : Result.fail(false, "删除失败");
    }
}

PermissionController

权限接口

import com.travel.term.common.aop.RequestPermission;
import com.travel.term.common.constant.PermissionConstant;
import com.travel.term.common.data.resultAndReq.ReqPage;
import com.travel.term.common.data.resultAndReq.Result;
import com.travel.term.entity.Permission;
import com.travel.term.service.PermissionService;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;

/**
 * (Permission)表控制层
 *
 * @author cai
 * @since 2023-12-14 12:33:49
 */
@RestController
@Tag(name = "权限接口信息", description = "权限接口信息")
@RequestMapping("/permission")
public class PermissionController {
    /**
     * 服务对象
     */
    @Resource
    private PermissionService permissionService;

    /**
     * 分页查询所有数据
     *
     * @param page 分页对象
     * @return 所有数据
     */
    @GetMapping
    @RequestPermission(name = ("admin:" + PermissionConstant.READ))
    public Result<List<Permission>> selectAll(ReqPage page) {
        return Result.success((this.permissionService.list()));
    }

}

RoleController

角色接口

import com.github.pagehelper.PageHelper;
import com.travel.term.common.aop.RequestPermission;
import com.travel.term.common.constant.PermissionConstant;
import com.travel.term.common.data.resultAndReq.PageResult;
import com.travel.term.common.data.resultAndReq.ReqPage;
import com.travel.term.common.data.resultAndReq.Result;
import com.travel.term.entity.Role;
import com.travel.term.entity.req.ReqRole;
import com.travel.term.service.RoleService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * (User)表控制层
 *
 * @author cai
 * @since 2023-12-13
 */
@RestController
@RequestMapping("/role")
@Tag(name = "角色接口", description = "角色信息接口")
@Slf4j
public class RoleController {
    /**
     * 服务对象
     */
    @Resource
    private RoleService roleService;

    /**
     * 分页查询所有数据
     *
     * @param page 分页对象
     * @return 所有数据
     */
    @RequestPermission(name = ("admin:" + PermissionConstant.READ))
    @Operation(summary = "返回所有分页信息", description = "")
    @GetMapping
    public Result<PageResult<Role>> selectAll(ReqPage page, ReqRole reqRole) {
        PageHelper.startPage(page.getPageNum(), page.getPageSize());
        return Result.success(new PageResult<>(roleService.list(reqRole)), "查询成功");
    }

    /**
     * 通过主键查询单条数据
     *
     * @param id 主键
     * @return 单条数据
     */
    @GetMapping("/{id}")
    @RequestPermission(name = PermissionConstant.READ)
    public Result<Role> selectOne(@PathVariable("id") String id) {
        return Result.success(roleService.getById(id), "查询成功");
    }

    /**
     * 新增数据
     *
     * @param role 实体对象
     * @return 新增结果
     */
    @PostMapping
    @RequestPermission(name = ("superAdmin:" + PermissionConstant.READ))
    public Result<Boolean> insert(@RequestBody Role role) {
        return Result.success(roleService.save(role), "添加成功");
    }

    /**
     * 修改数据
     *
     * @param role 实体对象
     * @return 修改结果
     */
    @PutMapping
    @RequestPermission(name = PermissionConstant.READ)
    public Result<Boolean> update(@RequestBody Role role) {
        return Result.success(roleService.updateById(role), "修改成功");
    }

    /**
     * 删除数据
     *
     * @param ids 主键集合
     * @return 删除结果
     */
    @DeleteMapping("/batch/{ids}")
    @RequestPermission(name = ("superAdmin:" + PermissionConstant.READ))
    public Result<Boolean> batchDelete(@Parameter(description = "ids为路径参数,是由多个id以英文,分隔开的字符串") @PathVariable("ids") String ids) {
        String[] newIds = ids.split(",");
        return Result.success(roleService.removeByIds(Arrays.asList(newIds)), "删除成功");
    }

    /**
     * 返回集合role
     *
     * @return
     */
    @GetMapping("/backen/list")
    @RequestPermission(name = PermissionConstant.READ)
    public Result<List<Role>> getList() {
        List<Role> list = roleService.list(new ReqRole()).stream().filter(item -> item != null && !item.getId().equals("1")).collect(Collectors.toList());
        return Result.success(list, "查询成功");
    }

    /**
     * 根据id删除角色信息
     *
     * @param id
     * @return
     */
    @RequestPermission(name = ("superAdmin:" + PermissionConstant.READ))
    @DeleteMapping("/{id}")
    public Result<Boolean> delete(@PathVariable("id") Long id) {
        return roleService.deleteById(id) ? Result.success("删除成功") : Result.fail("删除失败");
    }


}

UserController

用户接口

import com.github.pagehelper.PageHelper;
import com.travel.term.common.aop.RequestPermission;
import com.travel.term.common.constant.PermissionConstant;
import com.travel.term.common.data.resultAndReq.PageResult;
import com.travel.term.common.data.resultAndReq.ReqPage;
import com.travel.term.common.data.resultAndReq.Result;
import com.travel.term.common.utils.EncryptUtils;
import com.travel.term.common.utils.StringUtils;
import com.travel.term.entity.Role;
import com.travel.term.entity.User;
import com.travel.term.entity.req.ReqUser;
import com.travel.term.service.RoleService;
import com.travel.term.service.UserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;

/**
 * (User)表控制层
 *
 * @author cai
 * @since 2023-12-04 22:02:00
 */
@RestController
@RequestMapping("/user")
@Tag(name = "用户信息", description = "用户信息接口")
@Slf4j
public class UserController {
    /**
     * 服务对象
     */
    @Resource
    private UserService userService;

    @Resource
    private RoleService roleService;

    /**
     * 分页查询所有数据
     *
     * @param page 分页对象
     * @return 所有数据
     */
    @Operation(summary = "返回所有信息", description = "")
    @GetMapping
    @RequestPermission(name = ("admin:" + PermissionConstant.READ))
    public Result<PageResult<User>> selectAll(ReqPage page, ReqUser reqUser) {
        PageHelper.startPage(page.getPageNum(), page.getPageSize());
        return Result.success(userService.list(reqUser), "查询成功");
    }

    /**
     * 通过主键查询单条数据
     *
     * @param id 主键
     * @return 单条数据
     */
    @GetMapping("/{id}")
    @RequestPermission(name = PermissionConstant.READ)
    public Result<User> selectOne(@PathVariable("id") String id) {
        User user = userService.getById(id);
        if (!StringUtils.nullOrEmpty(user)) {
            Role roleName = roleService.getById(user.getRoleId());
            user.setRoleName(!StringUtils.nullOrEmpty(roleName) ? roleName.getName() : "");
        }
        user.setPassword(EncryptUtils.decrypt(user.getPassword()));
        return Result.success(user, "查询成功");
    }

    /**
     * 新增数据
     *
     * @param user 实体对象
     * @return 新增结果
     */
    @PostMapping
    @RequestPermission(name = ("superAdmin:" + PermissionConstant.READ))
    public Result<Boolean> insert(@RequestBody User user) {
        user.setPassword(EncryptUtils.kaisaEncrypt(user.getPassword()));
        return Result.success(userService.save(user), "添加成功");
    }

    /**
     * 修改数据
     *
     * @param user 实体对象
     * @return 修改结果
     */
    @PutMapping
    @RequestPermission(name = ("superAdmin:" + PermissionConstant.READ))
    public Result<Boolean> update(@RequestBody User user) {
        if (user.getId().equals("1")) {
            return Result.fail("不允许下线超级管理员");
        }
        user.setPassword(EncryptUtils.kaisaEncrypt(user.getPassword()));
        return Result.success(userService.updateById(user), "修改成功");
    }

    /**
     * 删除数据
     *
     * @param ids 主键集合
     * @return 删除结果
     */
    @DeleteMapping("/batch/{ids}")
    @RequestPermission(name = ("superAdmin:" + PermissionConstant.READ))
    public Result<Boolean> deleteBatch(@PathVariable("ids") String ids) {
        List<String> newIds = Arrays.asList(ids.split(","));
        return Result.success(userService.removeByIds(newIds), "删除成功");
    }

    /**
     * 根据id删除用户
     *
     * @param id
     * @return
     */
    @DeleteMapping("/{id}")
    public Result<Boolean> delete(@PathVariable("id") String id) {
        if (id.equals("1")) {
            return Result.fail("超级管理员不允许注销");
        }
        return userService.removeById(id) ? Result.success("删除成功") : Result.fail("删除失败");
    }

    /**
     * PC端用户注册
     *
     * @param user
     * @return
     */
    @PostMapping("/register")
    public Result<Boolean> register(@RequestBody User user) {
        System.out.println(user);
        return userService.register(user);
    }

    /**
     * 检测用户名手机号,邮箱是否重复
     *
     * @param checkColumn
     * @return
     */
    @GetMapping("/check")
    public Result<Boolean> check(String checkColumn) {
        return userService.checkInfo(checkColumn);
    }
}

entity层

实体类对象层

req.ReqLoginUser

登陆接收数据实体类

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

@Data
@Schema(description = "", name = "登录接口接收参数")
public class ReqLoginUser {
    @Schema(name = "account", description = "登陆账户,可为账号、手机号、邮箱号")
    private String account;
    @Schema(name = "password", description = "账户密码")
    private String password;
}

req.ReqIFile

文件操作接收数据实体类

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

@Schema(description = "role分页查询对象")
@Data
public class ReqIFile {
    @Schema(description = "创建者")
    private String createBy;
    @Schema(description = "是否私有(0不私有,1私有)")
    private String ifPrivate = String.valueOf(0);
}

req.ReqRole

角色接收数据实体类

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

@Schema(description="role分页查询对象")
@Data
public class ReqRole {
    @Schema(description = "角色名")
    private String name;
    @Schema(description = "权限ids,前端传过来应该是所需权限的id值的组合(多个id用英文字符,分割形成的字符串)")
    private String permissionIds;
}

req.ReqUser

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

@Schema(description="user接收数据对象")
@Data
public class ReqUser {
    @Schema(description = "账号")
    private String account;
    @Schema(description = "电话")
    private String phone;
    @Schema(description = "邮箱地址")
    private String email;
    @Schema(description = "性别(男性为0女性为1)")
    private Integer gender;
    @Schema(description = "角色表id")
    private Integer roleId;
    @Schema(description = "状态,默认为1启动")
    private Integer status;
}

IFile

import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;

/**
 * 文件表(File)表实体类
 *
 * @author cai
 * @since 2024-01-26 20:07:20
 */
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@Schema(description = "file对象")
@Data
@TableName("file")
public class IFile {
    private static final long serialVersionUID = 1L;

    @Schema(description = "唯一id")
    private String id;
    @Schema(description = "文件地址")
    private String url;
    @Schema(description = "文件名")
    private String name;
    @Schema(description = "文件类型")
    private String type;
    @Schema(description = "创建者")
    private String createBy;
    @Schema(description = "是否私有(0不私有,1私有)")
    private Integer ifPrivate = 0;

}

Permission

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;


/**
 * (Permission)表实体类
 *
 * @author cai
 * @since 2023-12-14 12:34:49
 */
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@Schema(description="Permission对象")
@Data
@TableName("permission")
public class Permission {
    @Schema(description = "唯一id")
    @TableId(type = IdType.ASSIGN_ID)
    private Long id;
    @Schema(description = "描述")
    private String description;
    @Schema(description = "表达式")
    private String expression;

}

Role

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;

/**
 * (Role)表实体类
 *
 * @author cai
 * @since 2023-12-13
 */
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@Schema(description="role对象")
@Data
@TableName("role")
public class Role {
    @Schema(description = "唯一id")
    @TableId(type = IdType.AUTO)
    private String id;
    @Schema(description = "角色名")
    private String name;
    @Schema(description = "角色描述")
    private String description;
    @Schema(description = "权限ids")
    private String permissionIds;
    @Schema(description = "前端权限名字渲染,不参与表的映射")
    @TableField(exist = false)
    private String permissionName;
}

User

import java.util.Date;

import cn.hutool.core.date.DateTime;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.springframework.format.annotation.DateTimeFormat;

/**
 * (User)表实体类
 *
 * @author cai
 * @since 2023-12-04 22:02:02
 */
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@Schema(description = "user对象")
@Data
@TableName("user")
public class User {
    @Schema(description = "唯一id")
    @TableId(type = IdType.ASSIGN_ID)
    private String id;
    @Schema(description = "账号")
    private String account;
    @Schema(description = "电话")
    private String phone;
    @Schema(description = "邮箱地址")
    private String email;
    @Schema(description = "密码")
    private String password;
    @Schema(description = "性别(男性为0女性为1)")
    private Integer gender;
    @Schema(description = "年龄")
    private Integer age;
    @Schema(description = "出生日期")
    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date birth;
    @Schema(description = "角色表id")
    private Integer roleId;
    @Schema(description = "状态,默认为1启动")
    private Integer status = 1;
    @Schema(description = "创建时间")
    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date createDate = DateTime.now();
    @TableField(exist = false)
    private String roleName;
    @Schema(description = "用户头像")
    private String avatar;
}

mapper层

IFileMapper

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.travel.term.entity.IFile;

public interface IFileMapper extends BaseMapper<IFile> {
}

PermissionMapper

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.travel.term.entity.Permission;

/**
 * (Permission)表数据库访问层
 *
 * @author cai
 * @since 2023-12-14 12:34:20
 */
public interface PermissionMapper extends BaseMapper<Permission> {

}

RoleMapper

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.travel.term.entity.Role;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import java.util.List;

/**
 * (Role)表数据库访问层
 *
 * @author cai
 * @since 2023-12-13
 */

public interface RoleMapper extends BaseMapper<Role> {

//    @Select("select description from permission where id in (#{permissionIds})")
    List<String> queryIds(@Param("permissionIds") List<String> permissionIds);
}

UserMapper

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.travel.term.entity.Role;
import com.travel.term.entity.User;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import java.util.Arrays;
import java.util.List;

/**
 * (User)表数据库访问层
 *
 * @author cai
 * @since 2023-12-04 22:02:01
 */

public interface UserMapper extends BaseMapper<User> {

    User checkAccount(@Param("account") String account);

    @Select("select * from role")
    List<Role> roleList();
}

service层

IFileService

import com.baomidou.mybatisplus.extension.service.IService;
import com.travel.term.common.data.resultAndReq.PageResult;
import com.travel.term.entity.IFile;
import com.travel.term.entity.req.ReqIFile;

import java.io.File;

public interface IFileService extends IService<IFile> {
    File checkAddr();

    PageResult<IFile> list(ReqIFile reqIFile);

    boolean deleteFileByPath(IFile file, String path);
}

PermissionService

import com.baomidou.mybatisplus.extension.service.IService;
import com.travel.term.entity.Permission;
import com.travel.term.entity.Role;

/**
 * (User)表服务接口
 *
 * @author cai
 * @since 2023-12-04 22:02:03
 */
public interface PermissionService extends IService<Permission> {

}

RoleService

import com.baomidou.mybatisplus.extension.service.IService;
import com.travel.term.entity.Role;
import com.travel.term.entity.User;
import com.travel.term.entity.req.ReqRole;

import java.util.Arrays;
import java.util.List;

/**
 * (User)表服务接口
 *
 * @author cai
 * @since 2023-12-04 22:02:03
 */
public interface RoleService extends IService<Role> {

    Boolean deleteById(Long id);

    List<Role> list(ReqRole reqRole);
}

UserService

import com.baomidou.mybatisplus.extension.service.IService;
import com.travel.term.common.data.resultAndReq.PageResult;
import com.travel.term.common.data.resultAndReq.Result;
import com.travel.term.entity.User;
import com.travel.term.entity.req.ReqUser;
import com.travel.term.entity.req.ReqLoginUser;

/**
 * (User)表服务接口
 *
 * @author cai
 * @since 2023-12-04 22:02:03
 */
public interface UserService extends IService<User> {

    User checkUserInfo(ReqLoginUser loginUserVo);

    Result<Boolean> register(User user);

    PageResult<User> list(ReqUser reqUser);

    Result<Boolean> checkInfo(String checkColumn);
}

impl

IFileServiceImpl
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.travel.term.common.data.properties.FileProperties;
import com.travel.term.common.data.resultAndReq.PageResult;
import com.travel.term.common.data.resultAndReq.Result;
import com.travel.term.common.exception.CommonException;
import com.travel.term.common.utils.FileUtils;
import com.travel.term.common.utils.StringUtils;
import com.travel.term.entity.IFile;
import com.travel.term.entity.User;
import com.travel.term.entity.req.ReqIFile;
import com.travel.term.mapper.IFileMapper;
import com.travel.term.service.IFileService;
import com.travel.term.service.UserService;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.util.List;

@Service
public class IFileServiceImpl extends ServiceImpl<IFileMapper, IFile> implements IFileService {

    @Resource
    private FileProperties fileProperties;

    @Resource
    private UserService userService;

    /**
     * 检查当前操作系统
     *
     * @return
     */
    @Override
    public File checkAddr() {
        File fileDir = new File("C:/");
        // 判断是否为windows系统
        if (fileDir.exists()) {
            fileDir = new File("C:/travel");
        } else {
            // 否则按照默认路径
            fileDir = new File(fileProperties.getLocation());
        }
        if (!fileDir.exists() && !fileDir.isDirectory()) {
            fileDir.mkdirs();
        }
        return fileDir;
    }

    @Override
    public PageResult<IFile> list(ReqIFile reqIFile) {
        LambdaQueryWrapper<IFile> queryWrapper = new LambdaQueryWrapper();
        queryWrapper.eq(!StringUtils.nullOrEmpty(reqIFile.getIfPrivate()), IFile::getIfPrivate, Integer.parseInt(reqIFile.getIfPrivate()))
                .like(!StringUtils.nullOrEmpty(reqIFile.getCreateBy()), IFile::getCreateBy, reqIFile.getCreateBy());
        List<IFile> list = this.list(queryWrapper);
        PageResult<IFile> pageResult = new PageResult<>(list);
        return pageResult;
    }

    @Override
    public boolean deleteFileByPath(IFile file, String path) {
        // 获取请求头信息
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String actualHeaderValue = request.getHeader("token");
        //处理token获取用户id
        String[] split = actualHeaderValue.split("-");
        String id = split[split.length - 1];
        //通过id获取用户名
        User user = userService.getById(id);
        if (StringUtils.nullOrEmpty(user)) {
            throw new CommonException("服务器出错,请稍后重试");
        }
        //判断用户名和文件创建角色是否相同
        if (!user.getAccount().equals(file.getCreateBy()) && file.getIfPrivate() != 0) {
            return false;
        }
        if (this.removeById(file.getId())) {
            if (!FileUtils.deleteFile(path)) {
                System.out.println("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
                this.save(file);
                return false;
            }
            return true;
        }
        return false;
    }
}
PermissionServiceImpl
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.travel.term.entity.Permission;
import com.travel.term.mapper.PermissionMapper;
import com.travel.term.service.PermissionService;
import org.springframework.stereotype.Service;

/**
 * (User)表服务实现类
 *
 * @author cai
 * @since 2023-12-13
 */
@Service
public class PermissionServiceImpl extends ServiceImpl<PermissionMapper, Permission> implements PermissionService {

}
RoleServiceImpl
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.travel.term.common.utils.StringUtils;
import com.travel.term.entity.Permission;
import com.travel.term.entity.Role;
import com.travel.term.entity.User;
import com.travel.term.entity.req.ReqRole;
import com.travel.term.mapper.RoleMapper;
import com.travel.term.mapper.UserMapper;
import com.travel.term.service.RoleService;
import com.travel.term.service.UserService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * (User)表服务实现类
 *
 * @author cai
 * @since 2023-12-13
 */
@Service
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {

    @Resource
    private UserService userService;

    @Override
    public Boolean deleteById(Long id) {
        // 创建一个集合存放id
        List<Long> ids = new ArrayList<>();
        ids.add(id);
        // 查询是否能被删除
        return this.couldDelete(ids) ? this.removeById(id) : false;
    }

    /**
     * 分页查询业务实现
     *
     * @param reqRole
     * @return
     */
    @Override
    public List<Role> list(ReqRole reqRole) {
        LambdaQueryWrapper<Role> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(!StringUtils.nullOrEmpty(reqRole.getName()), Role::getName, reqRole.getName());
        // 模糊查询名字
        List<Role> list = this.list(queryWrapper);
        // 将permissionsIds转化为名字
        list.stream().peek(item -> {
            if (item.getPermissionIds() != null && item.getPermissionIds() != "") {
                //转为list集合
                List<String> split = Arrays.asList(item.getPermissionIds().split(","));
                // 查询权限名字组
                List<String> names = this.getBaseMapper().queryIds(split);
                item.setPermissionName(names.toString());
                System.out.println(split);
            }
        }).collect(Collectors.toList());
        //若有权限条件查询则进行查询
        if (StringUtils.nullOrEmpty(reqRole.getPermissionIds())) {
            return list;
        }
        List<String> ids = Arrays.asList(reqRole.getPermissionIds().split(","));
        // 对权限查询进行模糊处理
        return list.stream().map(item -> {
            if (StringUtils.nullOrEmpty(item.getPermissionIds())) {
                return null;
            }
            String[] split = item.getPermissionIds().split(",");
            List<String> idList = Arrays.asList(split);
            // 查询是否包含要的id
            return idList.containsAll(ids) ? item : null;
        }).collect(Collectors.toList());
    }

    /**
     * 查询role是否被引用
     *
     * @param ids
     * @return
     */
    private Boolean couldDelete(List<Long> ids) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(ids.size() != 0, User::getRoleId, ids);
        // 查询要删除的roleId是否被user引用,确保数据库外键约束不被破坏
        List<User> list = userService.list(queryWrapper);
        return list.size() == 0;
    }
}
UserServiceImpl
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.travel.term.common.constant.RoleConstant;
import com.travel.term.common.data.resultAndReq.PageResult;
import com.travel.term.common.data.resultAndReq.Result;
import com.travel.term.common.utils.EncryptUtils;
import com.travel.term.common.utils.StringUtils;
import com.travel.term.entity.Role;
import com.travel.term.entity.req.ReqUser;
import com.travel.term.entity.req.ReqLoginUser;
import com.travel.term.mapper.UserMapper;
import com.travel.term.entity.User;
import com.travel.term.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

/**
 * (User)表服务实现类
 *
 * @author cai
 * @since 2023-12-04 22:02:03
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Override
    public User checkUserInfo(ReqLoginUser loginUserVo) {
        log.info(loginUserVo.toString());
        // 检查账号是否存在
        User user = this.baseMapper.checkAccount(loginUserVo.getAccount());
        if (StringUtils.nullOrEmpty(user)) {
            // 没有该账号
            return new User().setId("-1");
        }
        if (user.getStatus() == 0) {
            return user;
        }
        // 检查密码是否正确
        // 对密码进行解密
        String password = EncryptUtils.decrypt(user.getPassword());
        if (!StringUtils.nullOrEmpty(loginUserVo.getPassword()) && password.equals(loginUserVo.getPassword())) {
            return user;
        }
        return null;
    }

    @Override
    public Result<Boolean> register(User user) {
        String password = EncryptUtils.kaisaEncrypt(user.getPassword());
        user.setPassword(password);
        user.setRoleId(RoleConstant.用户);
        boolean save = this.save(user);
        return save == true ? Result.success("注册成功") : Result.fail("注册失败");
    }

    @Override
    public PageResult<User> list(ReqUser reqUser) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(!StringUtils.nullOrEmpty(reqUser.getAccount()), User::getAccount, reqUser.getAccount())
                .eq(!StringUtils.nullOrEmpty(reqUser.getPhone()), User::getPhone, reqUser.getPhone())
                .eq(!StringUtils.nullOrEmpty(reqUser.getEmail()), User::getEmail, reqUser.getEmail())
                .eq(!StringUtils.nullOrEmpty(reqUser.getGender()), User::getGender, reqUser.getGender())
                .eq(!StringUtils.nullOrEmpty(reqUser.getRoleId()), User::getRoleId, reqUser.getRoleId())
                .eq(!StringUtils.nullOrEmpty(reqUser.getStatus()), User::getStatus, reqUser.getStatus());
        //查询
        List<User> list = this.list(queryWrapper);
        // 把全部role查出来减少数据库访问操作
        HashMap<String, String> newRoleMap = (HashMap<String, String>) this.baseMapper.roleList().stream().collect(Collectors.toMap(Role::getId, Role::getName));
        //roleId映射名字
        list.stream().peek(item -> {
            // 访问数据库获取名字
            if (StringUtils.nullOrEmpty(item.getRoleId()) || StringUtils.nullOrEmpty(newRoleMap.get(item.getRoleId().toString()))) {
                System.out.println(item.getRoleId() + "  " + newRoleMap.get(item.getRoleId().toString()));
                item.setRoleName("");
            } else {
                item.setRoleName(newRoleMap.get(item.getRoleId().toString()));
            }
        }).collect(Collectors.toList());
        return new PageResult<>(list);
    }

    @Override
    public Result<Boolean> checkInfo(String checkColumn) {
        return StringUtils.nullOrEmpty(this.baseMapper.checkAccount(checkColumn)) ? Result.success("不重复") : Result.fail("已存在,不允许重复");
    }
}

TravelSystemApplication

启动类,相当于入口

import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.travel.term.mapper.*")
@Slf4j
public class TravelSystemApplication {

    public static void main(String[] args) {
        SpringApplication.run(TravelSystemApplication.class, args);
        log.info("http://localhost:8848/swagger-ui/index.html");
    }

}

resource

mapper

IFileMapper.xml
<?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="com.travel.term.mapper.IFileMapper">
</mapper>
PermissionMapper.xml
<?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="com.travel.term.mapper.PermissionMapper">
</mapper>
RoleMapper.xml
<?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="com.travel.term.mapper.RoleMapper">
    <select id="queryIds" resultType="java.lang.String">
        select description from permission
        <where>
            id in
            <foreach collection="permissionIds" open="(" close=")" item="id" separator=",">
                #{id}
            </foreach>
        </where>
    </select>
</mapper>
UserMapper.xml
<?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="com.travel.term.mapper.UserMapper">

    <resultMap type="com.travel.term.entity.User" id="UserMap">
        <result property="id" column="id" jdbcType="VARCHAR"/>
        <result property="account" column="account" jdbcType="VARCHAR"/>
        <result property="phone" column="phone" jdbcType="VARCHAR"/>
        <result property="email" column="email" jdbcType="VARCHAR"/>
        <result property="password" column="password" jdbcType="VARCHAR"/>
        <result property="gender" column="gender" jdbcType="INTEGER"/>
        <result property="age" column="age" jdbcType="INTEGER"/>
        <result property="birth" column="birth" jdbcType="TIMESTAMP"/>
        <result property="roleId" column="role_id" jdbcType="INTEGER"/>
    </resultMap>

    <!-- 批量插入 -->
    <insert id="insertBatch" keyProperty="id" useGeneratedKeys="true">
        insert into travel.user(account, phone, email, password, gender, age, birth, role_id)
        values
        <foreach collection="entities" item="entity" separator=",">
        (#{entity.account}, #{entity.phone}, #{entity.email}, #{entity.password}, #{entity.gender}, #{entity.age}, #{entity.birth}, #{entity.roleId})
        </foreach>
    </insert>
    <!-- 批量插入或按主键更新 -->
    <insert id="insertOrUpdateBatch" keyProperty="id" useGeneratedKeys="true">
        insert into travel.user(account, phone, email, password, gender, age, birth, role_id)
        values
        <foreach collection="entities" item="entity" separator=",">
            (#{entity.account}, #{entity.phone}, #{entity.email}, #{entity.password}, #{entity.gender}, #{entity.age}, #{entity.birth}, #{entity.roleId})
        </foreach>
        on duplicate key update
         account = values(account) , phone = values(phone) , email = values(email) , password = values(password) , gender = values(gender) , age = values(age) , birth = values(birth) , role_id = values(role_id)     </insert>
    <select id="checkAccount" parameterType="String" resultType="com.travel.term.entity.User">
        select *
        from user u
        <where>
            u.account = #{account} or u.phone = #{account} or u.email = #{account}
        </where>;
    </select>

</mapper>

templates(动态模版文件)

application.yaml(配置文件)

部署

打包

maven打包,可直接使用idea的maven插件

在traget下有个打包完的jar包

部署

将jar包在服务器上启动

使用命令如下:

#后台启动
nohup java -jar -Xms128m -Xmx256m travel-system-0.0.1-SNAPSHOT.jar >/dev/null 2>&1 &

通过指令查看是否运行成功

ps -ef | grep travel-system-0.0.1-SNAPSHOT.jar

  • 22
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Vue3简单图书管理系统可以包括以下功能和权限设计: 1. 登录和权限管理:系统可以有不同的用户角色,如超级管理员、图书管理员和普通读者。超级管理员拥有所有权限,图书管理员有图书管理权限,普通读者只有查询和借阅权限。登录时需要验证用户身份和权限。 2. 图书管理:管理员可以进行图书的新增、删除、修改和查询操作。新增图书时需要填写相关信息,如书名、作者、出版社等。删除图书时需要确认操作,修改图书时可以编辑相关信息。查询图书可以根据关键字进行搜索。 3. 借阅管理:读者可以进行图书的借阅操作。在借阅记录的待还借阅页面,读者可以通过账号搜索自己的借阅记录,并进行还书操作。还书后,借阅记录会从待还借阅页面移除,同时图书的库存会增加1。 4. 权限管理:系统中的每个按钮都进行权限管理,不同角色的用户拥有不同的权限。超级管理员拥有所有权限,图书管理员拥有图书管理权限,普通读者只有查询和借阅权限。后端接口也进行权限标识,只有拥有相应权限的用户才能访问相关接口。 总结起来,Vue3简单图书管理系统可以实现登录和权限管理、图书管理、借阅管理等功能,并根据用户角色进行权限控制。 #### 引用[.reference_title] - *1* *2* *3* [项目设计-基于SpringBoot和Vue开发的图书管理系统](https://blog.csdn.net/m0_37723366/article/details/127715157)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值