【Spring】简单的登录案例和配套知识

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 1. 演示一下 Spring 管理类的模式2. 用户登录案例2.1 准备的对象和其功能2.1.1 User2.1.2 UserController2.1.3 UserService2.1.4 UserDao2.1.5 AppConfig2.1.6 DemoApplication2.2 各对象之间的依赖关系2.3 IOC 带来的一个好处3. Spring 中的日志打印3.1 Spring 官方提供的方式3.2 lombok 提供的方法3.2 日志打印级别3.3 修改当前日志级别

1. 演示一下 Spring 管理类的模式

下面代码在第一次打印 Person 对象的时候,pid = 0,name = null,


第二次打印的时候,pid 有值,name 依旧是 null


第三次打印的时候,pid 和 name 都有值


而 pid 和 name 是由不同的两个类赋值的,说明这两个类被注入了同一个 Bean,由此可知 Spring 管理对象采用单例模式


一般在 Java 中,表过程的对象总是以单例的方式出现,表数据的对象无法使用单例管理,所以,一般让 Spring 管理的对象大多是表过程的对象(不是绝对的)

@Component
public class Person {
    int pid;
    String name;
    @Override
    public String toString() {
        return "Person{" +
                "pid=" + pid +
                ", name='" + name + '\'' +
                '}';
    }
}
@Component
public class Person1 {
    @Autowired
    public void usePerson1(Person person) {
        System.out.println("usePerson1(), person = " + person);
        person.pid = 20221024;
    }
}
@Component
public class Person2 {
    @Autowired
    public void usePerson2(Person person) {
        System.out.println("usePerson2(), person = " + person);
        person.name = "hsq";
    }
}
@SpringBootApplication
public class DemoApplication {
   public static void main(String[] args) throws Exception {
      ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
      Person bean = context.getBean(Person.class);
      System.out.println(bean);
   }
}

80.png


2. 用户登录案例

没有用到 Web 的形式,仅仅只是从控制台输入输出,然后将数据存入数据库


2.1 准备的对象和其功能

在 IOC 之外的场景下,Bean 注入的注释标签就要有一些区分了

2.1.1 User

表示用户本身(属性,构造方法,toString)


public class User {
    public Integer uid;
    public String username;
    public String password;
    public User() {}
    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }
    public User(Integer uid, String username, String password) {
        this.uid = uid;
        this.username = username;
        this.password = password;
    }
    @Override
    public String toString() {
        return "User{" +
                "uid=" + uid +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return Objects.equals(uid, user.uid);
    }
    @Override
    public int hashCode() {
        return Objects.hash(uid);
    }
}

2.1.2 UserController

进行用户输入、输出的操作(不同于 Web 的模式,这里的输入输出通过 Scanner(System.in) 和 System.out 控制)


@Controller
public class UserController {
    // 依赖输入、输出,我们自己不强调一定是标准输入输出
    private final Scanner scanner;
    private final PrintWriter writer;
    private final UserService userService;
    // 全部让 Spring 帮我们注入
    @Autowired
    public UserController(Scanner scanner, PrintWriter writer, UserService userService) {
        this.scanner = scanner;
        this.writer = writer;
        this.userService = userService;
    }
    public void run() throws Exception {
        while (true) {
            writer.print("请选择是注册还是登录:");
            writer.flush();
            String func = scanner.nextLine();
            if (func.equals("注册")) {
                writer.println("您选择了【注册】功能,接下来请输入用户名和密码");
                writer.print("请输入用户: ");
                writer.flush();
                String username = scanner.nextLine();
                writer.print("请输入密码: ");
                writer.flush();
                String password = scanner.nextLine();
                User user = userService.register(username, password);
                writer.println("注册完成,您的用户信息是: " + user);
            } else if (func.equals("登录")) {
                writer.println("您选择了【登录】功能,接下来请输入用户名和密码");
                writer.print("请输入用户: ");
                writer.flush();
                String username = scanner.nextLine();
                writer.print("请输入密码: ");
                writer.flush();
                String password = scanner.nextLine();
                User user = userService.login(username, password);
                if (user == null) {
                    writer.println("登录失败");
                } else {
                    writer.println("登录成功,您的用户信息是: " + user);
                }
            }
        }
    }
}

2.1.3 UserService

进行必要的数据操作,进行密码的加密和解密\


@Service
public class UserService {
    // UserService 对象依赖 UserDao 对象
    // 直接使用注入的方式
    private final UserDao userDao;
    // 构造方法注入
    @Autowired
    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }
    public User register(String username, String password) throws Exception {
        // 1. 密码的 hash 加密
        String salt = BCrypt.gensalt();
        password = BCrypt.hashpw(password, salt);
        // 2. 进行插入
        User user = new User(username, password);
        userDao.insert(user);
        // 3. 返回构造完成的用户对象
        return user;
    }
    public User login(String username, String password) throws Exception {
        // 1. 先查询用户
        User user = userDao.selectOneByUsername(username);
        if (user == null) {
            return null;
        }
        // 2. 进行密码的比较
        if (!BCrypt.checkpw(password, user.password)) {
            return null;
        }
        // 3. 返回构造完成的用户对象
        return user;
    }
}

上面代码中用到的 BCrypt 算法是一种密码加密算法,代码篇幅过长,有需要的大佬可以去自行下载 —— BCrypt 加密算法下载

2.1.4 UserDao

对数据库进行操作



@Repository
public class UserDao {
    private static final Logger log = LoggerFactory.getLogger(UserDao.class);
    // 依赖 DataSource 对象才能完成
    // 需要 Spring 帮我们注入 DataSource 对象
    private final DataSource dataSource;
    // 使用构造方法注入(依赖注入)
    @Autowired
    public UserDao(DataSource dataSource) {
        this.dataSource = dataSource;
    }
    public void insert(User user) throws Exception {
        try (Connection c = dataSource.getConnection()) {
            String sql = "insert into users (username, password) values (?, ?)";
            try (PreparedStatement ps = c.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
                ps.setString(1, user.username);
                ps.setString(2, user.password);
                log.info("执行的 SQL = {} ", ps);
                ps.executeUpdate();
                try (ResultSet rs = ps.getGeneratedKeys()) {
                    rs.next();
                    user.uid = rs.getInt(1);
                }
            }
        }
    }
    public User selectOneByUsername(String username) throws Exception {
        try (Connection c = dataSource.getConnection()) {
            String sql = "select uid, username, password from users where username = ?";
            try (PreparedStatement ps = c.prepareStatement(sql)) {
                ps.setString(1, username);
                log.info("执行的 SQL = {} ", ps);
                try (ResultSet rs = ps.executeQuery()) {
                    if (!rs.next()) {
                        return null;
                    }
                    return new User(
                            rs.getInt("uid"),
                            rs.getString("username"),
                            rs.getString("password")
                    );
                }
            }
        }
    }
}

2.1.5 AppConfig

因为案例只是我自己写的,所以前面代码中所注入的 Bean,我需要自行注册进 Spring,这里采用方法注册。并且在这里配置数据库


@Configuration
public class AppConfig {
    @Bean
    public Scanner scanner() {
        return new Scanner(System.in);
    }
    @Bean
    public PrintWriter writer() {
        // PrintStream -> PrintWriter
        PrintStream printStream = System.out;
        return new PrintWriter(printStream, true);
    }
    @Bean
    public DataSource dataSource() {
        MysqlDataSource dataSource = new MysqlDataSource();
        dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/demo?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai");
        dataSource.setUser(" ");  // 数据库用户名
        dataSource.setPassword(" ");  // 数据库密码
        return dataSource;
    }
}

2.1.6 DemoApplication

主类,程序的入口,调用 UserController 中的 run() 方法开始程序


@SpringBootApplication
public class DemoApplication {
   public static void main(String[] args) throws Exception {
      ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
      UserController userController = context.getBean(UserController.class);
      userController.run();
   }
}

2.2 各对象之间的依赖关系


81.png


2.3 IOC 带来的一个好处

我们去依赖抽象的概念,不需要具体的实现


好处是,我们可以很方便的替换背后的依赖对象。比如:刚才我们依赖的 Scanner 对象是从标准输入读取的,我们可以很方便的替换成读取文件的方式


只需修改 AppConfig 对象中的 Scanner 方法为以下即可


public Scanner scanner() throws FileNotFoundException {
//        return new Scanner(System.in);
        File file = new File("input.txt");
        return new Scanner(file, "UTF-8");
}

3. Spring 中的日志打印

3.1 Spring 官方提供的方式

先得到 log 对象,再调用其中方法打印日志即可

private static final Logger log = LoggerFactory.getLogger(UserDao.class);
log.info("执行的 SQL = {} ", ps);

3.2 lombok 提供的方法

使用 @Slf4j 注释修饰此类,然后使用 log 调用方法打印即可,前提是必须要有 lombok 插件


3.2 日志打印级别

比当前日志级别低的打印方式不会有结果

如:当前日志级别为 info 时,那么用 debug 打印不会有结果


82.png


3.3 修改当前日志级别

默认日志级别是 info ,我们可以在配置文件中修改当前日志级别

在配置文件中写入如下代码,即可将 com.hsq.demo 包下的日志文件修改为 debug


logging.level.com.hsq.demo=debug
相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
3月前
|
SQL Java 测试技术
在Spring boot中 使用JWT和过滤器实现登录认证
在Spring boot中 使用JWT和过滤器实现登录认证
210 0
|
5月前
|
存储 Java 数据安全/隐私保护
Spring Boot中实现邮箱登录/注册接口
Spring Boot中实现邮箱登录/注册接口
|
3月前
|
Java 数据库连接 Spring
后端框架入门超详细 三部曲 Spring 、SpringMVC、Mybatis、SSM框架整合案例 【爆肝整理五万字】
文章是关于Spring、SpringMVC、Mybatis三个后端框架的超详细入门教程,包括基础知识讲解、代码案例及SSM框架整合的实战应用,旨在帮助读者全面理解并掌握这些框架的使用。
后端框架入门超详细 三部曲 Spring 、SpringMVC、Mybatis、SSM框架整合案例 【爆肝整理五万字】
|
3月前
|
JSON 安全 Java
|
3月前
|
Java API Spring
Spring5入门到实战------1、Spring5框架概述、入门案例
这篇文章是Spring5框架的入门教程,概述了Spring框架的核心概念和特点,并通过一个创建普通Java类的案例,详细演示了从下载Spring核心Jar包、创建配置文件、编写测试代码到运行测试结果的完整流程,涵盖了Spring IOC容器的使用和依赖注入的基本用法。
|
5月前
|
存储 安全 Java
Spring Security 6.x OAuth2登录认证源码分析
上一篇介绍了Spring Security框架中身份认证的架构设计,本篇就OAuth2客户端登录认证的实现源码做一些分析。
223 2
Spring Security 6.x OAuth2登录认证源码分析
|
4月前
|
开发框架 Java 开发者
Spring框架的最新功能与应用案例解析
Spring框架的最新功能与应用案例解析
|
5月前
|
存储 前端开发 Java
Spring第三课,Lombok工具包下载,对应图书管理系统列表和登录界面的后端代码,分层思想
Spring第三课,Lombok工具包下载,对应图书管理系统列表和登录界面的后端代码,分层思想
|
4月前
|
存储 Java 数据中心
Spring Boot与微服务治理框架的集成成功案例
Spring Boot与微服务治理框架的集成成功案例
|
4月前
|
前端开发 Java 数据库连接
Spring6(一):入门案例
Spring6(一):入门案例
50 0