【keel】4. 实现数据库交互

1、pom.xml设置

		<!-- MySQL驱动 -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>8.0.28</version>
		</dependency>

		<!-- Spring Data JPA -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.18.30</version>
			<scope>provided</scope>
		</dependency>

2、生成entity

package com.huangssssx.keel.repository.entity;
import java.time.LocalDateTime;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Data;

@Data
@Entity
@Table(name = "sys_user")
public class SysUser {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name="username",nullable = false)
    private String username;

    @Column(name = "password",nullable = false)
    private String password;

    private String nickname;

    private String email;

    private String phone;

    @Column(name="status",nullable = false)
    private Boolean status;

    @Column(name="create_time",nullable = false)
    private LocalDateTime createTime;

    @Column(name = "update_time")
    private LocalDateTime updateTime;

    @Column(name="last_login_time")
    private LocalDateTime lastLoginTime;
}
  1. @Data 注解
    • 所在的包及相关依赖@Data 注解来自于Lombok库。Lombok是一个Java库,它通过在编译阶段自动生成一些样板代码(如getter、setter、toString、equals和hashCode等方法)来减少开发人员的工作量。需要在项目中添加Lombok依赖才能使用这个注解。
    • 作用
      • 自动为类生成getter和setter方法。例如,如果有一个属性 private String name;,使用 @Data 后,编译器会自动生成 public String getName() 和 public void setName(String name) 方法。
      • 生成 toString 方法,用于方便地将对象以字符串的形式输出,默认会包含类的所有属性及其值。
      • 生成 equals 和 hashCode 方法,这在比较对象是否相等以及在使用对象作为哈希表(如 HashMap)的键时非常有用。
    • 示例import lombok.Data; @Data public class User { private Long id; private String username; private String password; } 在这个 User 类中,由于有 @Data 注解,就不需要手动编写 idusername 和 password 的getter、setter等方法,编译器会自动生成这些方法,方便了代码的编写和维护。
  2. @Entity 注解
    • 所在的包及相关依赖@Entity 属于Java Persistence API(JPA)的一部分,位于 javax.persistence.Entity 包中。使用时通常需要在项目中添加JPA相关的依赖(如 spring - boot - starter - data - jpa)。
    • 作用
      • 用于将一个Java类标记为实体类,表明这个类与数据库中的表相对应。在JPA的持久化操作中,实体类是数据存储和检索的核心概念。
      • 实体类的实例可以被JPA的 EntityManager 管理,能够进行保存(persist)、更新(merge)、删除(remove)等数据库操作。
    • 示例import javax.persistence.Entity; @Entity public class User { // 类的成员变量和方法 } 当这个 User 类被标注为 @Entity 后,JPA会认为它是一个实体,可以与数据库中的表进行关联操作。
  3. @Table(name = "sys_user") 注解
    • 所在的包及相关依赖@Table 也属于JPA的一部分,位于 javax.persistence.Table 包中。同样依赖JPA相关的库。
    • 作用
      • 用于指定实体类对应的数据库表名。在上面的示例中,@Table(name = "sys_user") 表示这个实体类对应的数据库表名字是 sys_user
      • 如果没有使用这个注解,JPA通常会默认使用实体类的类名作为表名(将类名按照一定规则转换为表名,如将大写字母转换为小写字母,并在单词之间添加下划线等)。
    • 示例import javax.persistence.Entity; import javax.persistence.Table; @Entity @Table(name = "sys_user") public class User { // 类的成员变量和方法 } 这里明确告诉JPA,User 实体类对应的数据库表是 sys_user

3、创建Repository接口

package com.huangssssx.keel.repository.dao;
import org.springframework.data.jpa.repository.JpaRepository;

import com.huangssssx.keel.repository.entity.SysUser;

public interface SysUserRepository extends JpaRepository<SysUser, Long> {
    
}

这个接口创建后将自动提供一些基础的DB功能,

  • save(SysUser entity):用于保存一个 SysUser 实体对象到数据库。如果对象的主键(这里是 Long 类型)不存在,就执行插入操作;如果主键存在,就执行更新操作。
  • findById(Long id):根据给定的主键 id 查找对应的 SysUser 实体对象。返回值是一个 Optional<SysUser>,这样可以方便地处理可能不存在的情况。
  • existsById(Long id):检查数据库中是否存在给定主键 id 的 SysUser 实体。
  • delete(SysUser entity) 和 deleteById(Long id):分别用于删除一个实体对象和根据主键删除实体对象。

4、用户名密码校验

这里使用到了 SecurityConfig.java ,这个类之所以能被包含入spring框架中是因为使用了多个注解,使spring明白这个文件的意义:

  1. @Configuration 注解
    • 作用
      • 当一个类被标注了 @Configuration 注解时,它表明这个类是一个配置类。在 Spring 框架中,配置类用于定义和配置应用程序中的各种 Bean(即组件)。Spring 会在启动时扫描带有 @Configuration 注解的类,并处理其中定义的 Bean 方法。
    • 原理
      • Spring 使用 CGLIB(动态代理库)在运行时为标注了 @Configuration 的类创建代理对象。这样做的目的是确保配置类中的 @Bean 方法只被调用一次,避免多次创建相同的 Bean 实例。例如,在上述 SecurityConfig 类中,当 Spring 扫描到这个类时,会识别出它是一个配置类,并处理其中的 @Bean 方法。
  2. @EnableWebSecurity 注解
    • 作用
      • 这个注解用于启用 Spring Security 的 Web 安全功能。它是一个复合注解,其内部包含了 @Configuration 注解,并且导入了一些 Spring Security 相关的配置类,如 WebSecurityConfiguration。它告诉 Spring 框架要为 Web 应用程序应用安全配置。
    • 原理
      • 当 Spring 处理带有 @EnableWebSecurity 注解的类时,它会导入必要的安全配置类和组件。例如,它会引入默认的安全过滤器链、用户认证和授权机制等。在 SecurityConfig 类中,@EnableWebSecurity 注解使得 Spring 能够识别这是一个与 Web 安全相关的配置类,并应用相关的安全策略。
  3. @Bean 方法
    • 作用
      • 在 SecurityConfig 类中,有多个 @Bean 方法,如 securityFilterChainpasswordEncoderuserDetailsService 和 authenticationManager。这些方法用于向 Spring 容器中注册 Bean 实例。例如,passwordEncoder 方法返回一个 BCryptPasswordEncoder 实例,它将被 Spring 管理,并且可以在需要密码编码的地方注入使用。
    • 原理
      • Spring 在处理 @Configuration 类时,会调用其中的 @Bean 方法,并将方法返回的对象作为 Bean 实例存储在 Spring 容器中。这些 Bean 实例可以在应用程序的其他地方通过依赖注入的方式使用。例如,userDetailsService 方法返回的 InMemoryUserDetailsManager 实例可以在用户认证过程中被 Spring Security 使用。

综上所述,SecurityConfig 类能够被包含入 Spring 框架中,是因为它使用了 @Configuration 和 @EnableWebSecurity 注解来标识自己是一个 Spring 配置类和启用 Web 安全功能,并且通过 @Bean 方法向 Spring 容器中注册了各种安全相关的组件。

  • 首先需要修改获取user的方式,我们这里使用数据库搜索获取用户信息:
    @Bean
    public UserDetailsService userDetailsService() {
        return username -> {
            SysUser user = sysUserRepository.findByUsername(username)
                .orElseThrow(() -> new UsernameNotFoundException("用户不存在: " + username));
            
            return User.builder()
                .username(user.getUsername())
                .password(user.getPassword())
                .roles("USER")  // 可以根据需要设置角色
                .build();
        };
    }

设定密码的加密方式

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

设定authenticationManager,然后在其中使用这两个bean

    @Bean
    public AuthenticationManager authenticationManager() {
        DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
        authProvider.setUserDetailsService(userDetailsService());
        authProvider.setPasswordEncoder(passwordEncoder());
        
        return new ProviderManager(authProvider);
    }

这样就将我们需要的功能放入了切片中

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部