SpringBoot开发之Spring基础

SpringBoot开发之Spring基础


我们接着上次继续学习,上次我们学习了单一职责原则以及知道了每一个模块需要一个接口+一个实现类,那么如果我想切换各模块,查询不同数据库该怎么办呢,请接着往下看

一、开闭原则

1.我们不能修改已有的类,我们想要切换不同的类,那么我们就需要新建一个新的实现类UserDaoImpl1

在这里插入图片描述
在这里插入图片描述

2.在UserDaoImpl1中我们可以从不同表获取值

在这里插入图片描述

package com.zou.dao.impl;

import com.zou.dao.UserDao;

public class UserDaoImpl1 implements UserDao {
    
    
    public String findUser() {
    
    
//        todo 数据库请求获取用户名

        return "从数据库admin表中取出来的张海航";
    }
}

3.我们要切换到UserDaoImpl1这个实现类,就只要修改MyServlet一行代码即可,其他均无需修改,这也就符合开闭原则,软件的扩展性也越强啦

在这里插入图片描述

package com.zou.controller;

import com.zou.dao.UserDao;
import com.zou.dao.impl.UserDaoImpl;
import com.zou.dao.impl.UserDaoImpl1;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
//http://localhost:8080/JavaWeb_war/MyServlet


@WebServlet(name = "MyServlet", value = "/MyServlet")
public class MyServlet extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
//      输出html语句
//        response.getWriter().println("<h1>Hello World MyServlet!</h1>");
//        通过Servlet转发jsp页面
//        jsp页面负责html网页相关的,Servlet负责请求java逻辑相关的代码
//        todo 从数据库中请求用户名的数据库
//        Java JDBC连接数据库步骤
//        1.打开数据库连接 2.SQL语句请求数据库得到数据 3.数据处理封装 4.关闭数据库
//        单一职责原则:一个类不能太累了
//        新建一个包,把所有与数据库操作有关的放到这个包下
//        每一个模块需要一个接口+一个实现类
//        里氏替换原则->java设计模式
//        开闭原则
//        不修改MyServlet任何代码
//        1.把创建的类名写到配置文件(xml/properties)中
//        2.从配置文件中读类的名字
//        3.代码动态的把读到的类名的对象创建出来->反射
        UserDao userdao=new UserDaoImpl1();
        String name="从数据库中取出来的testName";
        request.setAttribute("name",userdao.findUser());
        request.getRequestDispatcher("index.jsp").forward(request,response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    

    }
}

4.点击运行,访问Servlet,查询到了不同表的数据

在这里插入图片描述
那我们能不能不修改MyServlet任何代码也实现上面的功能呢

二、不修改MyServlet任何代码

方法

1.把创建的类名写到配置文件(xml/properties)中
2.从配置文件中读类的名字
3.代码动态的把读到的类名的对象创建出来->反射

三、Spring框架

1.关于Spring

(1)Spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的开源容器框架,用来解决企业项目开发中的复杂问题

(2)发展历史

  • 2004年3月,1.0发布
  • 2006年10月,2.0发布
  • 2009年12月,3.0发布
  • 2013年12月,4.0发布
  • 2017年9月,5.0发布

2.Spring体系结构

在这里插入图片描述
在这里插入图片描述

3.第一个Spring程序->控制反转(IOC)

(1)创建新项目Spring,选择Maven项目

在这里插入图片描述
在这里插入图片描述

(2)设置好放置路径,将JavaWeb删掉,他们就是属于同一级别啦

在这里插入图片描述

(3)选择Archetype为org.apache.maven.archetypes:maven-archetype-quickstart(专属IOC功能),其他配置与之前一样,然后点击Create创建

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(4)IOC功能

1.开闭原则,不修改MyServlet任何代码
2.把创建的类名写到配置文件(xml/properties)中
3.从配置文件中读类的名字
4.代码动态的把读到的类名的对象创建出来->反射 JavaEE设计模式
5.Spring->IOC(控制反转)->解耦

控制反转:在使用Spring框架之后,对象的实例不再由调用者来创建,而是由Spring容器来创建,Spring容器负责控制程序之间的关系,而不是由调用者的程序代码直接控制。这样,控制权由应用代码转移到了Spring容器,控制权发生了反转,这就是控制反转。

(5)复制JavaWeb项目中的dao层到Spring项目中,我们就不需要重新写代码啦,但是记得需要修改他们的包名,否则会报错

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(6)接下来我们在pom.xml中引入Spring依赖包,并点击同步按钮

在这里插入图片描述

 <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.3.22</version>
    </dependency>

(7)在main包下新建一个包resources

在这里插入图片描述
在这里插入图片描述

(8)在resources文件夹下新建xml文件,选择Spring Config,起名为applicationContext

在这里插入图片描述

在这里插入图片描述

(9)把创建的类名写到配置文件(xml/properties)中,在applicationContext.xml中敲入代码并指定类名,注意要加上包名,再给它的对象起个名

在这里插入图片描述

(10)完成后我们在APP.java中进行调用,也就是从配置文件中读类的名字

在这里插入图片描述

(11)接着我们开始取对象,并打印输出,点击运行,这时我们不要再用Tomcat启动了,直接点击旁边的运行按钮即可,就可以看到数据库里的数据啦

在这里插入图片描述
在这里插入图片描述

(12)我们可以按照上面的写法,同时,我们还有更简单更方便的里氏替换原则:用UserDaoImpl的接口,也就是父类UserDao来取

在这里插入图片描述

(13)最后打印输出它的方法,点击运行

在这里插入图片描述

在这里插入图片描述

4.接下来我们实现上篇说的开闭原则,也就是不修改App任何代码进行查询数据库的切换,怎么做呢?

(1)我们只要在applicationContext.xml中修改类名即可

在这里插入图片描述

(2)我们运行看看,得到数据库里另一表的数据,这样就真正做到了开闭原则,不修改App任何代码进行查询数据库的切换

在这里插入图片描述

(3)接着在APP.java中引用两个类,并做比较,大家觉得结果是什么,会是true还是false呢

在这里插入图片描述

(4)点击运行看看,结果是false,那为什么呢?

在这里插入图片描述

(5)原因:在java中,我们引用一个对象,就会创建一个堆空间,并且有一个栈空间指向它,当我们又引用一个对象时,它会创建一个新的堆空间,又有一个新的栈空间指向它,而比较的是内存地址,而这两者是不一样的

在这里插入图片描述

(6)我们现在用里氏替换原则再来比较一下,结果又会是什么样呢?

在这里插入图片描述

(7)点击运行,发现是true,这又怎么理解呢?

在这里插入图片描述

(8)原因:用里氏替换原则运行代码后,它会创建一个Spring容器,里面存放的就是我们要取的数据库,当两个对象分别去取的时候,其实他们取的是同一个,所以他们是一样的

在这里插入图片描述

(9)因此,我们更倾向于用里氏替换原则,它可以节省内存,也叫单利模式

(10)现在我们在applicationContext.xml中增加一行代码,继续运行,结果竟然是false,因为它就对应着第一种写法,singleton就对应着单利模式

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.Spring依赖注入

(1)首先新建一个文件夹为service

在这里插入图片描述

在这里插入图片描述

(2)在service文件夹下创建UserService类

在这里插入图片描述

package org.example.service;

import org.example.dao.UserDao;
import org.example.dao.impl.UserDaoImpl;

public class UserService {
    
    
    UserDao userDao=new UserDaoImpl();
    public String findUser() {
    
    
//        todo 数据库请求获取用户名

        return userDao.findUser();
    }
}

(3)修改APP.java代码,用UserService来输出

在这里插入图片描述

 UserService userService=new UserService();
 System.out.println(userService.findUser());

(4)点击运行,没有问题

在这里插入图片描述

(5)但可以有更好的方法,和前面一样利用里氏替换原则,在applicationContext.xml增加一个service节点

在这里插入图片描述

 <bean class="org.example.service.UserService" id="userService">
 </bean>

(6)接着修改APP.java代码

在这里插入图片描述

 UserService userService=(UserService) applicationContext.getBean("userService");
 System.out.println(userService.findUser());

(7)接着运行看看,结果一样,但是实现了解耦,更方便

在这里插入图片描述

(8)接下来修改UserService代码,不用new方法,我们给它创建方法,不需要手敲,有简便方法,点击鼠标右键,选择Generate

在这里插入图片描述

(9)选择Getter and Setter方法,点击OK

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

package org.example.service;

import org.example.dao.UserDao;
import org.example.dao.impl.UserDaoImpl;

public class UserService {
    
    
    UserDao userDao;

    public UserDao getUserDao() {
    
    
        return userDao;
    }

    public void setUserDao(UserDao userDao) {
    
    
        this.userDao = userDao;
    }

    public String findUser() {
    
    
//        todo 数据库请求获取用户名

        return userDao.findUser();
    }
}

(10)修改APP.java代码, 用set方法对userService变量赋值

在这里插入图片描述

package org.example;

import org.example.dao.UserDao;
import org.example.dao.impl.UserDaoImpl;
import org.example.dao.impl.UserDaoImpl1;
import org.example.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Hello world!
 *
 */
public class App 
{
    
    
    public static void main( String[] args )
    //        开闭原则
//        不修改App任何代码
//        1.把创建的类名写到配置文件(xml/properties)中
//        2.从配置文件中读类的名字
//        3.代码动态的把读到的类名的对象创建出来->反射 JavaEE设计模式
//        Spring->IOC(控制反转)->解耦
//            引入Spring依赖包
    {
    
    
//        UserDao userDao1=new UserDaoImpl();
//        UserDao userDao2=new UserDaoImpl();
//        System.out.println(userDao1==userDao2);
//        System.out.println( "Hello World!" );
        ApplicationContext applicationContext= new ClassPathXmlApplicationContext("applicationContext.xml");
//        UserDaoImpl userDao = (UserDaoImpl) applicationContext.getBean("userDao");
//        里氏替换原则->用UserDaoImpl的接口,也就是父类UserDao来取
        UserDao userDao = (UserDao) applicationContext.getBean("userDao");
//        UserDao userDao1 = (UserDao) applicationContext.getBean("userDao");
//        System.out.println(userDao==userDao1);
//        UserService userService=new UserService();
//        System.out.println(userService.findUser());
//        用set方法对userService变量赋值
        UserService userService=(UserService) applicationContext.getBean("userService");
        userService.setUserDao(userDao);
        System.out.println(userService.findUser());
    }
}

(11)点击运行,没有问题,但是他们之间还是存在耦合性

在这里插入图片描述

(12)为此,我们使用依赖注入(DI),用Spring容器来决定

依赖注入(DI):从Spring容器角度来看,Spring容器负责将被依赖的对象赋值给调用者的成员变量,相当于为调用者注入它所依赖的实例,这就是Spring的依赖注入。

1.在applicationContext.xml中增加一行代码

在这里插入图片描述

2.修改APP.java代码,将 userService.setUserDao(userDao);注释掉

在这里插入图片描述

3.点击运行,还是正确的

在这里插入图片描述

6.Spring 基本类型String依赖注入

(1)在org.examole文件夹下新建包pojo,并创建一个实体类Person

在这里插入图片描述
在这里插入图片描述

(2)声明两个成员变量age和name,并且给他们增加Getter and Setter方法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

package org.example.pojo;

public class Person {
    
    
    private int age;
    private String name;

    public int getAge() {
    
    
        return age;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }
}

(3)在applicationContext.xml中增加Person节点

在这里插入图片描述

 <bean class="org.example.pojo.Person" id="person">
        
 </bean>

(4)在APP.java赋值并打印输出

在这里插入图片描述

        Person person=(Person) applicationContext.getBean("person");
        person.setAge(20);
        person.setName("哈哈哈");
        System.out.println(person.getAge());
        System.out.println(person.getName());

(5)点击运行

在这里插入图片描述

(6)我们还可以用Spring容器赋值,在applicationContext.xml中直接赋值

在这里插入图片描述

  <bean class="org.example.pojo.Person" id="person">
        <property name="name" value="哈哈哈"/>
        <property name="age" value="20"/>
  </bean>

(7)修改APP.java代码,并点击运行

在这里插入图片描述
在这里插入图片描述

7.Spring容器注解

(1)上面教大家任何解决耦合性,但是发现代码好像并没有减少,现在教大家方法既实现解耦又不用很多代码,applicationContext.xml中节点的代码全都可以删掉哦,我们只用一行代码就可以代替它们,一听就很方便吧

在这里插入图片描述

(2)在Person类中增加一个注解,Spring就会自动创建对象 id=person

在这里插入图片描述

package org.example.pojo;
import org.springframework.stereotype.Component;

//@Component Spring创建对象 id=person
//@Component默认不生效
@Component
public class Person {
    
    
    private int age;
    private String name;

    public int getAge() {
    
    
        return age;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }
}

(3)在applicationContext.xml中增加一行代码使注解生效

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="org.example"/>
<!--&lt;!&ndash;1.把创建的类名写到配置文件(xml/properties)中&ndash;&gt;-->
<!--&lt;!&ndash;    class:需要创建的类名字  id:创建的对象的名字&ndash;&gt;-->
<!--    <bean class="org.example.dao.impl.UserDaoImpl1" id="userDao">-->

<!--    </bean>-->
<!--    <bean class="org.example.service.UserService" id="userService">-->
<!--        <property name="userDao" ref="userDao"/>-->
<!--    </bean>-->
<!--    <bean class="org.example.pojo.Person" id="person">-->
<!--        <property name="name" value="哈哈哈"/>-->
<!--        <property name="age" value="20"/>-->
<!--    </bean>-->
</beans>

(4)点击运行,出现默认值0和null

在这里插入图片描述

(5)我们也可以给它们赋值,在Person类中增加一个注解@Value,注意:注解只能管到离它最近的那行代码

在这里插入图片描述

package org.example.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

//@Component Spring创建对象 id=person
//@Component默认不生效
@Component
public class Person {
    
    

    @Value("20")
    private int age;
    
    @Value("哈哈哈")
    private String name;

    public int getAge() {
    
    
        return age;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }
}

(6)点击运行,出现20和哈哈哈

在这里插入图片描述

(7)其他的类也一样可以加入注解,注意:有四个注解它们功能一模一样,只是为了区分而已。

@Component->其他层
@Service->Service层
@Repository->dao层
@Controller->Controller层

在这里插入图片描述

(8)我们不能在接口UserDao上加注解,只能加在它的实现类UserDaoImpl上

在这里插入图片描述

package org.example.dao.impl;


import org.example.dao.UserDao;
import org.springframework.stereotype.Repository;

@Repository
public class UserDaoImpl implements UserDao {
    
    
    public String findUser() {
    
    
//        todo 数据库请求获取用户名
        String name="从数据库中取出来的testName1111";
        return name;
    }
}

在这里插入图片描述

package org.example.dao.impl;

//import com.zou.dao.UserDao;
import org.example.dao.UserDao;
import org.springframework.stereotype.Repository;

@Repository
public class UserDaoImpl1 implements UserDao {
    
    
    public String findUser() {
    
    
//        todo 数据库请求获取用户名

        return "从数据库admin表中取出来的张海航";
    }
}

(9)给userDao赋值,否则运行会报错;在它上面加上 @Autowired注解,它可以实现自动注入

在这里插入图片描述
在这里插入图片描述

(10)点击运行,没有问题

在这里插入图片描述

(11)我们把Getter and Setter 方法去掉,运行同样没有问题

在这里插入图片描述
在这里插入图片描述

(12)当我们同时给两个实现类添加注解的时候,我们需要修改UserService代码,否则会报错;类型匹配有冲突时,Autowired注解就会按照名字匹配

在这里插入图片描述

package org.example.service;

import org.example.dao.UserDao;
import org.example.dao.impl.UserDaoImpl1;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;


@Service
public class UserService {
    
    
//    Autowired 自动注入
//    Autowired 替换set和get方法
    @Autowired
    UserDao userDaoImapl1;
//
//    public UserDao getUserDao() {
    
    
//        return userDao;
//    }
//
//    public void setUserDao(UserDao userDao) {
    
    
//        this.userDao = userDao;
//    }

    public String findUser() {
    
    
//        todo 数据库请求获取用户名

        return userDaoImapl1.findUser();
    }
}

四、资源下载

下载地址:SpringBoot开发之Spring基础

猜你喜欢

转载自blog.csdn.net/qq_61963074/article/details/127031740