SpringBoot开发之Spring基础
- 一、开闭原则
- 二、不修改MyServlet任何代码
- 三、Spring框架
-
- 1.关于Spring
- 2.Spring体系结构
- 3.第一个Spring程序->控制反转(IOC)
- (1)创建新项目Spring,选择Maven项目
-
- (2)设置好放置路径,将JavaWeb删掉,他们就是属于同一级别啦
- (3)选择Archetype为org.apache.maven.archetypes:maven-archetype-quickstart(专属IOC功能),其他配置与之前一样,然后点击Create创建
- (4)IOC功能
- (5)复制JavaWeb项目中的dao层到Spring项目中,我们就不需要重新写代码啦,但是记得需要修改他们的包名,否则会报错
- (6)接下来我们在pom.xml中引入Spring依赖包,并点击同步按钮
- (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类
- (3)修改APP.java代码,用UserService来输出
- (4)点击运行,没有问题
- (5)但可以有更好的方法,和前面一样利用里氏替换原则,在applicationContext.xml增加一个service节点
- (6)接着修改APP.java代码
- (7)接着运行看看,结果一样,但是实现了解耦,更方便
- (8)接下来修改UserService代码,不用new方法,我们给它创建方法,不需要手敲,有简便方法,点击鼠标右键,选择Generate
- (9)选择Getter and Setter方法,点击OK
- (10)修改APP.java代码, 用set方法对userService变量赋值
- (11)点击运行,没有问题,但是他们之间还是存在耦合性
- (12)为此,我们使用依赖注入(DI),用Spring容器来决定
- 6.Spring 基本类型String依赖注入
- 7.Spring容器注解
-
- (1)上面教大家任何解决耦合性,但是发现代码好像并没有减少,现在教大家方法既实现解耦又不用很多代码,applicationContext.xml中节点的代码全都可以删掉哦,我们只用一行代码就可以代替它们,一听就很方便吧
- (2)在Person类中增加一个注解,Spring就会自动创建对象 id=person
- (3)在applicationContext.xml中增加一行代码使注解生效
- (4)点击运行,出现默认值0和null
- (5)我们也可以给它们赋值,在Person类中增加一个注解@Value,注意:注解只能管到离它最近的那行代码
- (6)点击运行,出现20和哈哈哈
- (7)其他的类也一样可以加入注解,注意:有四个注解它们功能一模一样,只是为了区分而已。
- (8)我们不能在接口UserDao上加注解,只能加在它的实现类UserDaoImpl上
- (9)给userDao赋值,否则运行会报错;在它上面加上 @Autowired注解,它可以实现自动注入
- (10)点击运行,没有问题
- (11)我们把Getter and Setter 方法去掉,运行同样没有问题
- (12)当我们同时给两个实现类添加注解的时候,我们需要修改UserService代码,否则会报错;类型匹配有冲突时,Autowired注解就会按照名字匹配
- 四、资源下载
我们接着上次继续学习,上次我们学习了单一职责原则以及知道了每一个模块需要一个接口+一个实现类,那么如果我想切换各模块,查询不同数据库该怎么办呢,请接着往下看
一、开闭原则
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"/>
<!--<!–1.把创建的类名写到配置文件(xml/properties)中–>-->
<!--<!– class:需要创建的类名字 id:创建的对象的名字–>-->
<!-- <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();
}
}