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


    本篇文章接着介绍 Spring 的相关知识,主要通过一个非常非常简单用户登录案例来介绍,各位大佬们路过记得赏小的一颗赞🤩


    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 + '\'' +
                    '}';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    @Component
    public class Person1 {
    
        @Autowired
        public void usePerson1(Person person) {
            System.out.println("usePerson1(), person = " + person);
            person.pid = 20221024;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    @Component
    public class Person2 {
    
        @Autowired
        public void usePerson2(Person person) {
            System.out.println("usePerson2(), person = " + person);
            person.name = "hsq";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    @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);
       }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    请添加图片描述

    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);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    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);
                    }
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    上面代码中用到的 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")
                        );
                    }
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    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();
       }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2.2 各对象之间的依赖关系

    请添加图片描述

    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");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3. Spring 中的日志打印

    3.1 Spring 官方提供的方式

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

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

    3.2 lombok 提供的方法

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

    3.2 日志打印级别

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

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

    请添加图片描述

    3.3 修改当前日志级别

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

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

    logging.level.com.hsq.demo=debug
    
    • 1
  • 相关阅读:
    django使用多个数据库实现
    第三十四章 Objects - 流接口类
    Docker---使用docker-compose部署confluence并进行数据迁移
    【前端】使用tesseract插件识别提取图片中的文字
    人工智能-线性回归2--房价预测、欠拟合过拟合、正则化、模型保存加载
    【小月电子】安路国产FPGA开发板系统学习教程-LESSON7串口通信
    浏览器开发者模式下只显示 XHR 请求应该怎么办
    Vue单文件组件的创建及三种暴露(分别、统一、默认)方式
    交叉导轨在自动化设备中的作用
    两条命令解决移动硬盘无法弹出的问题
  • 原文地址:https://blog.csdn.net/m0_56975154/article/details/127504015