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);
}
}
验证
访问无限制授权接口OK
访问授权限制接口OK
点击登录OK
作者:隔壁老郭
个性签名:独学而无友,则孤陋而寡闻。做一个灵魂有趣的人!
如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!
Java入门到入坟
万水千山总是情,打赏一分行不行,所以如果你心情还比较高兴,也是可以扫码打赏博主,哈哈哈(っ•̀ω•́)っ✎⁾⁾!