Springboot3.1+SpringSecurity+mybatis-plus3.5.3+knife4j-openapi3尝鲜

项目依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.gton</groupId>
    <artifactId>demo</artifactId>
    <version>3.0-SNAPSHOT</version>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus</artifactId>
            <version>3.5.3.1</version>
        </dependency>
        <!--Spring Boot 3 只支持OpenAPI3规范Knife4j提供的starter已经引用springdoc-openapi的jar,开发者需注意避免jar包冲突JDK版本必须 >= 17-->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
            <version>4.1.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.3.1</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.fastjson2</groupId>
            <artifactId>fastjson2</artifactId>
            <version>2.0.18</version>
        </dependency>
        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-core</artifactId>
            <version>6.1.0</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.graalvm.buildtools</groupId>
                <artifactId>native-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

项目启动类

@SpringBootApplication
@EnableTransactionManagement
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

常规配置

spring:
  # 数据源配置项
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/study?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
    driver-class-name: com.mysql.jdbc.Driver
    username: root # 数据库账号
    password: root # 数据库密码
    # HikariCP 自定义配置,对应 HikariConfig 配置属性类
    hikari:
      minimum-idle: 10 # 池中维护的最小空闲连接数,默认为 10 个。
      maximum-pool-size: 10 # 池中最大连接数,包括闲置和使用中的连接,默认为 10 个。
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher
# springdoc-openapi项目配置
springdoc:
  swagger-ui:
    path: /swagger-ui.html
    tags-sorter: alpha
    operations-sorter: alpha
  api-docs:
    path: /v3/api-docs
  group-configs:
    - group: 'default'
      paths-to-match: '/**'
      packages-to-scan:
        - com.gton.demo.entity
        - com.gton.demo.controller

# knife4j的增强配置,不需要增强可以不配
knife4j:
  enable: true
  setting:
    language: zh_cn
    swagger-model-name: "实体类"

# actuator 监控栈点
management:
  endpoints:
    web:
      exposure:
        include: '*'

# Mybatisplus配置
mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: isDel # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
      logic-delete-value: 0 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 1 # 逻辑未删除值(默认为 0)

配置SpringSecurity相关配置

此版本已经移除了WebSecurityConfigurerAdapter的扩展
SpringSecurity中文文档:https://springdoc.cn/spring-security;参考文档自行扩展定制

/**
 * @description:
 * @author: GuoTong
 * @createTime: 2023-06-01 21:44:49
 * @since JDK 1.8 OR 11
 **/

@Configuration
@SuppressWarnings("all")
@EnableMethodSecurity(securedEnabled = true, jsr250Enabled = true)
@RequiredArgsConstructor
public class SecurityConfig {

    @Value("spring.security.remenberKey:123456")
    private String remenberKey;

    @Autowired
    private SpringSecurityUserDetailService springSecurityUserDetailService;

    /**
     * Description:  资源授权配置
     *
     * @param http
     * @author: GuoTong
     * @date: 2023-06-16 21:35:54
     * @return:
     */
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.formLogin().and().csrf(csrf -> csrf.disable())
                //不通过Session获取SecurityContext
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED).and()
                // 下面开始设置权限
                .authorizeHttpRequests(authorize -> {
                            try {
                                authorize.requestMatchers("/doc.html",
                                        "/swagger-resources/configuration/ui",
                                        "/swagger*",
                                        "/swagger**/**",
                                        "/webjars/**",
                                        "/favicon.ico",
                                        "/**/*.css",
                                        "/**/*.js",
                                        "/**/*.png",
                                        "/**/*.gif",
                                        "/v3/**",
                                        "/**/*.ttf",
                                        "/actuator/**")
                                        .permitAll().
                                        requestMatchers("/static/**", "/resources/**").permitAll().
                                        requestMatchers("/gpLogin/**","/login","/logout").permitAll()
                                        // 配置权限
                                        .requestMatchers("/test")
                                        .hasAuthority("admin")
                                        // 其他地址的访问均需验证权限
                                        .anyRequest().authenticated().and().httpBasic();
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                ).logout().logoutSuccessHandler((request, response, authentication) -> SecurityContextHolder.clearContext()); // 登出后清楚请求的上下文,也就是用户信息;
        return http.build();
    }

    /**
     * 配置跨源访问(CORS)
     *
     * @return
     */
    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowedOriginPatterns(List.of("http://localhost:8083"));
        corsConfiguration.setAllowedMethods(List.of("GET", "POST", "OPTIONS", "DELETE", "PUT", "PATCH"));
        corsConfiguration.setAllowedHeaders(List.of("Access-Control-Allow-Origin", "X-Requested-With", "Origin", "Content-Type", "Accept", "Authorization"));
        corsConfiguration.setAllowCredentials(true);
        source.registerCorsConfiguration("/**", corsConfiguration);
        return source;
    }

    /**
     * 加密方式
     */
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }


    /**
     * springsecurity权限校验提供类
     *
     * @return
     */
    @Bean
    public AuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
        //使用自定义的用户校验
        authProvider.setUserDetailsService(springSecurityUserDetailService);
        authProvider.setPasswordEncoder(bCryptPasswordEncoder());
        return authProvider;

    }

    /**
     * 认证管理器,登录的时候参数会传给 authenticationManager
     */
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws
            Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }


    /**
     * Description:
     * <p>
     * TokenBasedRememberMeServices 生成一个 RememberMeAuthenticationToken,由 RememberMeAuthenticationProvider 处理。
     * 这个认证提供者和 TokenBasedRememberMeServices 之间共享一个密钥。
     * 此外,TokenBasedRememberMeServices 需要一个 UserDetailsService,它可以从中获取用户名和密码用于签名比较,
     * 并生成 RememberMeAuthenticationToken 以包含正确的 GrantedAuthority 实例。
     * TokenBasedRememberMeServices 还实现了 Spring Security 的 LogoutHandler 接口,
     * 样它就可以和 LogoutFilter 一起使用,让cookie自动清除。
     * <p>
     * 默认情况下,该实现使用SHA-256算法对令牌签名进行编码。为了验证令牌签名,从 algorithmName 中检索的算法被解析并使用。
     * 如果没有 algorithmName,将使用默认的匹配算法,即 SHA-256。
     * 你可以为签名编码和签名匹配指定不同的算法,这允许用户安全地升级到不同的编码算法,
     * 同时在没有 algorithmName 存在的情况下仍然能够验证旧的算法。要做到这一点,
     * 你可以把你定制的 TokenBasedRememberMeServices 指定为一个Bean,并在配置中使用它。
     */
    @Bean
    RememberMeServices rememberMeServices(UserDetailsService userDetailsService) {
        TokenBasedRememberMeServices.RememberMeTokenAlgorithm encodingAlgorithm = TokenBasedRememberMeServices.RememberMeTokenAlgorithm.SHA256;
        TokenBasedRememberMeServices rememberMe = new TokenBasedRememberMeServices(remenberKey, userDetailsService, encodingAlgorithm);
        rememberMe.setMatchingAlgorithm(TokenBasedRememberMeServices.RememberMeTokenAlgorithm.MD5);
        return rememberMe;
    }
}

全局异常处理

/**
 * @description: 全局异常处理:
 * @author: GuoTong
 * @createTime: 2022-11-27 11:17
 * @since JDK 1.8 OR 11
 **/
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    // 全局异常拦截
    @ExceptionHandler
    public Resp handlerException(Exception e) {
        e.printStackTrace();
        log.error("服务执行异常---->{}", e.getMessage());
        return Resp.error(e.getMessage());
    }


    @ExceptionHandler(value = SQLException.class)
    public Resp msgMySQLExecuteError(Exception e) {
        e.printStackTrace();
        log.error("Mysql执行异常");
        String message = e.getMessage();
        return Resp.error(message);
    }

    @ExceptionHandler(value = HttpMessageNotReadableException.class)
    public Resp msgNotFind(Exception e) {
        e.printStackTrace();
        log.error("请求错误");
        String message = e.getMessage();
        return Resp.error("请求内容未传递" + message);
    }

    @ExceptionHandler(value = NullPointerException.class)
    public Resp findNullPointerException(NullPointerException e) {
        log.error("出现空指针异常-----检查业务逻辑是否合理");
        String message = e.getMessage();
        return Resp.error("检查业务逻辑是否合理:" + message);
    }

    @ExceptionHandler(value = InternalAuthenticationServiceException.class)
    public Resp findInternalAuthenticationException(InternalAuthenticationServiceException e) {
        log.error("出现SpringSecurity异常-----怀疑当前用户不存在");
        String message = e.getMessage();
        return Resp.error("怀疑当前用户不存在:" + message);
    }
}

定制用户认证实现

/**
 * @description: implements UserDetailsService, UserDetailsPasswordService
 * @author: GuoTong
 * @createTime: 2023-06-16 21:38
 * @since JDK 1.8 OR 11
 **/

@Service
@Slf4j
@RequiredArgsConstructor
public class SpringSecurityUserDetailService implements UserDetailsService, UserDetailsPasswordService {

    @Autowired
    private final GpRuleService gpRuleService;


    /**
     * Description: 获取当前用户的方法,使用框架的上下文获取当前请求的用户
     *
     * @author: GuoTong
     * @date: 2023-06-16 21:40:45
     * @return:
     */
    public static Authentication getCurrentUser() {
        return SecurityContextHolder.getContext().getAuthentication();
    }

    /**
     * Description: UserDetails是springsecurity框架的授权用户实体
     * 如果用户更改密码了会重新刷新token或者退出登录,
     *
     * @author: GuoTong
     * @date: 2023-06-16 21:44:31
     * @return:
     */
    @Override
    public UserDetails updatePassword(UserDetails user, String newPassword) {
        boolean equals = user.getPassword().equals(newPassword);
        return equals ? user : null;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        log.info("进入查找用户的方法=====使用Mybatisplus的Model模式;无需Server和Mapper,直接让实体类具备CURD的操作");
        GpLogin userDO = new GpLogin().selectOne(new LambdaQueryWrapper<GpLogin>().eq(GpLogin::getUsername, username));
        if (userDO != null) {
            // 从权限表获取信息
            Long userId = userDO.getId();
            GpRule gpRule = gpRuleService.getOne(new LambdaQueryWrapper<GpRule>().eq(GpRule::getLoginId, userId));
            Integer roleGrade = gpRule != null ? gpRule.getRoleGrade() : 1000;
            Set<SimpleGrantedAuthority> permissions = new HashSet<>();
            if (roleGrade >= 3000) {
                log.info("超级管理员");
                permissions.add(new SimpleGrantedAuthority(ROLE_READ));
                permissions.add(new SimpleGrantedAuthority(ROLE_CREATE));
                permissions.add(new SimpleGrantedAuthority(ROLE_UPDATE));
                permissions.add(new SimpleGrantedAuthority(ROLE_DELETE));
            } else if (roleGrade >= 2000) {
                log.info("管理员");
                permissions.add(new SimpleGrantedAuthority(ROLE_READ));
                permissions.add(new SimpleGrantedAuthority(ROLE_UPDATE));
                permissions.add(new SimpleGrantedAuthority(ROLE_DELETE));
            } else {
                log.info("用户");
                permissions.add(new SimpleGrantedAuthority(ROLE_READ));
                permissions.add(new SimpleGrantedAuthority(ROLE_UPDATE));
            }
            //返回生成的用户
            GpLoginUser gpLoginUser = new GpLoginUser();
            gpLoginUser.setUsername(userDO.getUsername());
            gpLoginUser.setPassword(userDO.getPassword());
            gpLoginUser.setRoleGrade(roleGrade);
            gpLoginUser.setAuthorities(permissions);
            return gpLoginUser;
        }
        // 生成默认用户入库
        if (username.equals("noUser")) {
            GpLogin gpLogin = new GpLogin().setUsername("demoUser").setPassword(PasswordHandler.encodingBCryptPassword("demoPassword")).setWelcomeName("Hello World");
            gpLogin.insert();
            gpRuleService.save(new GpRule().setRoleGrade(1000).setLoginId(gpLogin.getId()).setState(1));
            log.info("生成默认的用户:demoUser ;默认的密码:demoPassword");
        }
        return null;
    }
}

SpringSecurity的用户实体实现

/**
 * @description: 用户登录
 * @author: GuoTong
 * @createTime: 2023-06-17 10:23
 * @since JDK 1.8 OR 11
 **/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class GpLoginUser extends GpLogin implements UserDetails, Serializable {


    public static final String ROLE_READ = "ROLE_read";
    public static final String ROLE_CREATE = "ROLE_create";
    public static final String ROLE_UPDATE = "ROLE_update";
    public static final String ROLE_DELETE = "ROLE_delete";

    private static final long serialVersionUID = 1L;

    /**
     * Description: 该用户所拥有的权限,如果细分为角色和权限,可以把两个都放到这个集合里面,
     * 比如ROLE_ADMIN,user:create可以同时存入
     *
     * @author: GuoTong
     * @date: 2023-06-16 21:49:14
     * @return:
     */
    private Collection<? extends GrantedAuthority> authorities;


    @Override
    public String getPassword() {
        return super.getPassword();
    }

    @Override
    public String getUsername() {
        return super.getUsername();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }


    @Override
    @JsonDeserialize(using = CustomAuthorityDeserializer.class)
    public Collection<? extends GrantedAuthority> getAuthorities() {
        List<SimpleGrantedAuthority> authorities = new ArrayList<>();
        if (this.roleGrade >= 3000) {
            authorities.add(new SimpleGrantedAuthority(ROLE_READ));
            authorities.add(new SimpleGrantedAuthority(ROLE_CREATE));
            authorities.add(new SimpleGrantedAuthority(ROLE_UPDATE));
            authorities.add(new SimpleGrantedAuthority(ROLE_DELETE));
        } else if (this.roleGrade >= 2000) {
            authorities.add(new SimpleGrantedAuthority(ROLE_READ));
            authorities.add(new SimpleGrantedAuthority(ROLE_UPDATE));
            authorities.add(new SimpleGrantedAuthority(ROLE_DELETE));
        } else {
            authorities.add(new SimpleGrantedAuthority(ROLE_READ));
            authorities.add(new SimpleGrantedAuthority(ROLE_UPDATE));
        }
        return authorities;
    }
}

spring security认证authorities反序列化处理

/**
 * @description: spring security认证authorities反序列化处理
 * @author: GuoTong
 * @createTime: 2023-06-17 10:11
 * @since JDK 1.8 OR 11
 **/
public class CustomAuthorityDeserializer extends JsonDeserializer {

    @Override
    public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {

        ObjectMapper mapper = (ObjectMapper) p.getCodec();
        JsonNode jsonNode = mapper.readTree(p);
        LinkedList<GrantedAuthority> grantedAuthorities = new LinkedList<>();
        Iterator<JsonNode> elements = jsonNode.elements();
        while (elements.hasNext()) {
            JsonNode next = elements.next();
            JsonNode authority = next.get("authority");//将得到的值放入链表 最终返回该链表
            grantedAuthorities.add(new SimpleGrantedAuthority(authority.asText()));
        }
        return grantedAuthorities;
    }
}

密码加密

/**
 * @description: 处理密文
 * @author: GuoTong
 * @createTime: 2023-06-17 11:01
 * @since JDK 1.8 OR 11
 **/
public class PasswordHandler {

    public static BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();

    public volatile static String mybatisPlusAESKey = "";

    public static String encodingBCryptPassword(String key) {
        return bCryptPasswordEncoder.encode(key);
    }

    public static boolean checkBCryptPassword(String password, String bCryptPassword) {
        return bCryptPasswordEncoder.matches(password, bCryptPassword);
    }


    public static String generateRandomKey() {
        if (StringUtils.isNotEmpty(mybatisPlusAESKey)) {
            return mybatisPlusAESKey;
        }
        mybatisPlusAESKey = AES.generateRandomKey();
        return mybatisPlusAESKey;
    }

    public static String setGenerateRandomKey(String yourselfKey) {
        mybatisPlusAESKey = yourselfKey;
        return mybatisPlusAESKey;
    }


    public static String getAESEncrypt(String data) {
        return AES.encrypt(data, mybatisPlusAESKey);
    }

    public static String getAESDecrypt(String data) {
        return AES.decrypt(data, mybatisPlusAESKey);
    }
}

Mybatis自动填充

/**
 * @description: 注解填充字段 @TableField(.. fill = FieldFill.INSERT) 生成器策略部分也可以配置!
 * @author: GuoTong
 * @createTime: 2023-06-17 09:54
 * @since JDK 1.8 OR 11
 **/
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill ....");
        // 起始版本 3.3.3(推荐)
        this.strictInsertFill(metaObject, "createTime", LocalDateTime::now, LocalDateTime.class);
        this.strictInsertFill(metaObject, "updateTime", LocalDateTime::now, LocalDateTime.class);

    }

    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start update fill ....");
        // 起始版本 3.3.3(推荐)
        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime::now, LocalDateTime.class);

    }
}

用户表 相关 ----实体类

/**
 * (GpLogin)表实体类
 * UserDetails
 *
 * @author 郭童
 * @since 2023-06-15 23:28:18
 */
@Data
@Accessors(chain = true)
@Schema(description = "GpLogin", title = "GpLogin")
public class GpLogin extends Model<GpLogin> implements Serializable {
    private static final long serialVersionUID = 1L;

    @TableId(value = "id", type = IdType.ASSIGN_ID)
    @Schema(description = "主键id", defaultValue = "1")
    private Long id;

    @TableField(value = "username")
    @Schema(description = "username", defaultValue = "username")
    private String username;

    @TableField(value = "password")
    @Schema(description = "password", defaultValue = "password")
    private String password;

    @TableField(value = "create_time", fill = FieldFill.INSERT)
    @Schema(description = "createTime", defaultValue = "create_time")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;

    @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
    @Schema(description = "updateTime", defaultValue = "update_time")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updateTime;

    @TableField(value = "welcome_name")
    @Schema(description = "welcomeName", defaultValue = "welcome_name")
    private String welcomeName;

    @TableField(value = "is_del")
    @Schema(description = "逻辑删除(0-标识删除,1-标识可用)")
    @TableLogic
    private Integer isDel;


    @TableField(exist = false)
    @Schema(description = "权限级别:1000普通用户 ,2000 会员  ,3000超级管理员", defaultValue = "1000")
    protected Integer roleGrade;


}

权限表 相关 ----实体类

/**
 * (GpRule)表实体类
 *
 * @author 郭童
 * @since 2023-06-16 21:58:14
 */
@Data
@Accessors(chain = true)
@Schema(description = "GpRule")
public class GpRule extends Model<GpRule> implements Serializable {
    private static final long serialVersionUID = 1L;

    @TableId(value = "id", type = IdType.ASSIGN_ID)
    @Schema(description = "ID")
    private Long id;

    @TableField(value = "login_id")
    @Schema(description = "登录表的_ID")
    private Long loginId;

    @TableField(value = "role_grade")
    @Schema(description = "权限级别:1000普通用户 ,2000 会员  ,3000超级管理员")
    private Integer roleGrade;

    @TableField(value = "create_time", fill = FieldFill.INSERT)
    @Schema(description = "创建时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;

    @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
    @Schema(description = "修改时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updateTime;

    @TableField(value = "state")
    @Schema(description = "是否有效:0无效,1有效")
    @TableLogic
    private Integer state;
}

用户表的Controller

/**
 * (GpLogin)表控制层
 *
 * @author 郭童
 * @since 2023-06-15 23:28:18
 */
@RestController
@RequestMapping("gpLogin")
@Tag(name = "(GpLogin)表控制层")
public class GpLoginController {
    /**
     * 服务对象
     */
    @Autowired
    private GpLoginService gpLoginService;

    @GetMapping("/getUser")
    public Resp getUserBySpringSecurity() {
        Authentication currentUser = SpringSecurityUserDetailService.getCurrentUser();
        Object userName = currentUser.getPrincipal();
        return Resp.Ok(userName);
    }

    /**
     * 分页查询数据
     *
     * @param limitRequest 查询实体
     * @return 所有数据
     */
    @PostMapping("/queryLimit")
    public Resp<BaseLimitResponse<GpLogin>> queryPage(@RequestBody BaseLimitRequest<GpLogin> limitRequest) {
        // 分页查询
        IPage<GpLogin> page = this.gpLoginService.queryLimitPage(limitRequest);
        // 封装返回结果集
        BaseLimitResponse<GpLogin> data = BaseLimitResponse.getInstance(page.getRecords(), page.getTotal(), page.getPages(), limitRequest.getPageIndex(), limitRequest.getPageSize());
        return Resp.Ok(data);
    }

    /**
     * 通过主键查询单条数据
     *
     * @param id 主键
     * @return 单条数据
     */
    @GetMapping("/queryOne/{id}")
    public Resp<GpLogin> selectOne(@PathVariable("id") Serializable id) {
        return Resp.Ok(this.gpLoginService.getById(id));
    }

    /**
     * 新增数据
     *
     * @param gpLogin 实体对象
     * @return 新增结果
     */
    @PostMapping("/save")
    public Resp<String> insert(@RequestBody GpLogin gpLogin) {
        boolean save = false;
        String executeMsg = null;
        try {
            gpLoginService.initUserAndRole(gpLogin);
            executeMsg = "新增成功,id 是:" + gpLogin.getId();
        } catch (Exception e) {
            executeMsg = e.getMessage();
        }
        return save ? Resp.Ok(executeMsg) : Resp.error(executeMsg);
    }

    /**
     * 批量新增数据
     *
     * @param gpLoginList 实体对象
     * @return 新增结果
     */
    @PostMapping("/saveBatch")
    public Resp<String> insertBatch(@RequestBody List<GpLogin> gpLoginList) {
        Integer save = 0;
        String executeMsg = null;
        try {
            save = this.gpLoginService.saveBatchByEasyBaseMapper(gpLoginList);
            executeMsg = "新增成功=>id 是:" + Arrays.toString(gpLoginList.stream().map(GpLogin::getId).toArray());
        } catch (Exception e) {
            executeMsg = e.getMessage();
        }
        return save > 0 ? Resp.Ok(executeMsg) : Resp.error(executeMsg);
    }


    /**
     * 修改数据
     *
     * @param gpLogin 实体对象
     * @return 修改结果
     */
    @PutMapping("/update")
    public Resp<String> update(@RequestBody GpLogin gpLogin) {

        boolean update = false;
        String executeMsg = null;
        try {
            update = this.gpLoginService.updateById(gpLogin);
            executeMsg = "修改成功,id 是:" + gpLogin.getId();
        } catch (Exception e) {
            executeMsg = e.getMessage();
        }
        return update ? Resp.Ok(executeMsg) : Resp.error(executeMsg);
    }

    /**
     * 删除数据
     *
     * @param idList 主键结合
     * @return 删除结果
     */
    @DeleteMapping("/dels")
    public Resp<String> delete(@RequestParam("idList") List<Long> idList) {
        boolean delNumber = false;
        String executeMsg = null;
        try {
            delNumber = this.gpLoginService.removeByIds(idList);
            executeMsg = "删除成功,ids 是:" + idList;
        } catch (Exception e) {
            executeMsg = e.getMessage();
        }
        return delNumber ? Resp.Ok(executeMsg) : Resp.error(executeMsg);
    }
}

用户表接口


import java.util.List;

/**
 * (GpLogin)表服务接口
 *
 * @author 郭童
 * @since 2023-06-15 23:28:18
 */
public interface GpLoginService extends IService<GpLogin> {

/**
     * Description:  分页查询
     *
     * @param limitRequest 分页查询参数
     * @author: GuoTong
     * @date: 2022-12-02 14:57:06
     * @return:com.baomidou.mybatisplus.core.metadata.IPage
     */
    IPage<GpLogin> queryLimitPage(BaseLimitRequest<GpLogin> limitRequest);
    
    
    /**
     * Description:  批量新增
     *
     * @param entityList
     * @author: GuoTong
     * @date: 2022-12-06 19:52:00
     * @return:Integer
     */
    Integer saveBatchByEasyBaseMapper(List<GpLogin> entityList);

    void initUserAndRole(GpLogin gpLogin);
}

用户表接口实现

/**
 * (GpLogin)表服务实现类
 *
 * @author 郭童
 * @since 2023-06-15 23:28:18
 */
@Service("gpLoginService")
public class GpLoginServiceImpl extends ServiceImpl<GpLoginMapper, GpLogin> implements GpLoginService {

    @Resource
    private GpLoginMapper gpLoginMapper;

    /**
     * Description:  分页查询
     *
     * @param limitRequest 分页查询参数
     * @author: GuoTong
     * @date: 2022-12-02 14:57:06
     * @return:com.baomidou.mybatisplus.core.metadata.IPage
     */
    @Override
    public IPage<GpLogin> queryLimitPage(BaseLimitRequest<GpLogin> limitRequest) {
        GpLogin requestBody = limitRequest.getRequestBody();
        long pageIndex = limitRequest.getPageIndex();
        long pageSize = limitRequest.getPageSize();
        IPage<GpLogin> page = new Page<>(pageIndex, pageSize);
        QueryWrapper<GpLogin> queryWrapper = new QueryWrapper<>();
        byte[] bytes = JSON.toJSONBytes(requestBody);
        JSONObject thisObj = JSON.parseObject(bytes);
        Set<Map.Entry<String, Object>> entries = thisObj.entrySet();
        for (Map.Entry<String, Object> entry : entries) {
            String key = entry.getKey();
            StringBuilder column = new StringBuilder();
            char[] chars = key.toCharArray();
            for (char aChar : chars) {
                if (Character.isUpperCase(aChar)) {
                    column.append("_");
                }
                column.append(aChar);
            }
            queryWrapper.eq(getValueIsBoolean(entry.getValue()), column.toString(), entry.getValue());
        }
        LocalDateTime beginTime = limitRequest.getBeginTime();
        LocalDateTime endTime = limitRequest.getEndTime();
        queryWrapper.ge(getValueIsBoolean(beginTime), "create_time", beginTime);
        queryWrapper.le(getValueIsBoolean(endTime), "create_time", beginTime);
        return gpLoginMapper.selectPage(page, queryWrapper);
    }

    /**
     * Description:  批量新增优化版
     *
     * @param entityList entityList
     * @author: GuoTong
     * @date: 2022-12-06 19:54:59
     * @return:java.lang.Integer
     */
    @Override
    public Integer saveBatchByEasyBaseMapper(List<GpLogin> entityList) {

        return this.saveBatch(entityList) ? entityList.size() : 0;
    }

    @Override
    @Transactional(timeout = 60000, rollbackFor = RuntimeException.class, propagation = Propagation.REQUIRED)
    public void initUserAndRole(GpLogin gpLogin) {
        // 注册用户
        gpLogin.setPassword(PasswordHandler.encodingBCryptPassword(gpLogin.getPassword()));
        this.save(gpLogin);
        // 分配权限
        GpRule gpRule = new GpRule();
        gpRule.setLoginId(gpLogin.getId()).
                setRoleGrade(gpLogin.getRoleGrade());
        gpRule.insert();
    }

    private boolean getValueIsBoolean(Object object) {

        if (object instanceof String) {
            return StringUtils.isNotEmpty((CharSequence) object);
        }
        return !Objects.isNull(object);
    }
}


略过权限表类似....

统一响应

/**
 * @description: 通用返回对象
 * 贫血型模型
 * @author: GuoTong
 * @createTime: 2022-09-24 13:16
 * @since JDK 1.8 OR 11
 **/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class Resp<T> implements Serializable {
    //状态码
    protected String code;

    //提示信息
    protected String msg;

    //返回的数据
    protected T data;


    /**
     * Description:常用返回数据抽离
     */
    public static <T> Resp<T> LoginOk() {
        return new Resp<T>().
                setCode(ContextCommonMsg.LOGIN_SUCCESS_CODE).
                setMsg(ContextCommonMsg.LOGIN_SUCCESS_MSG);
    }

    public static <T> Resp<T> LoginFail() {
        return new Resp<T>().
                setCode(ContextCommonMsg.LOGIN_FAIL_CODE).
                setMsg(ContextCommonMsg.LOGIN_FAIL_MSG);
    }

    public static <T> Resp<T> error(String errorMsg) {
        return new Resp<T>().
                setCode(ContextCommonMsg.FAIL_CODE).
                setMsg(errorMsg);
    }

    public static <T> Resp<T> error() {
        return new Resp<T>().
                setCode(ContextCommonMsg.FAIL_CODE).
                setMsg(ContextCommonMsg.FAIL_MSG);
    }

    public static <T> Resp<T> error(String errorMsg, String failCode) {
        return new Resp<T>().
                setCode(failCode).
                setMsg(errorMsg);
    }

    public static <T> Resp<T> error(String errorMsg, String failCode, T data) {
        return new Resp<T>().
                setCode(failCode).
                setData(data).
                setMsg(errorMsg);
    }

    public static <T> Resp<T> Ok(T data) {
        return new Resp<T>().
                setCode(ContextCommonMsg.SUCCESS_CODE).
                setMsg(ContextCommonMsg.SUCCESS_MSG).
                setData(data);
    }

    public static <T> Resp<T> Ok() {
        return new Resp<T>().
                setCode(ContextCommonMsg.SUCCESS_CODE).
                setMsg(ContextCommonMsg.SUCCESS_MSG);
    }

    public static <T> Resp<T> Ok(T data, String msg) {
        return new Resp<T>().
                setCode(ContextCommonMsg.SUCCESS_CODE).
                setMsg(msg).
                setData(data);
    }

    public static <T> Resp<T> Ok(T data, String msg, String successCode) {
        return new Resp<T>().
                setCode(successCode).
                setMsg(msg).
                setData(data);
    }

}

验证

image

访问无限制授权接口OK

image
image

访问授权限制接口OK

image

点击登录OK

image

posted on 2023-06-17 14:33  白嫖老郭  阅读(469)  评论(0编辑  收藏  举报

导航