目录
  1. 1. Spring
    1. 1.1. spring简介
      1. 1.1.1. spring是什么
      2. 1.1.2. spring的优势
      3. 1.1.3. spring 的体系结构
    2. 1.2. Spring 快速入门
      1. 1.2.1. 程序开发步骤
    3. 1.3. Spring 配置文件
      1. 1.3.1. Bean 标签的基本配置
        1. 1.3.1.1. 基本属性
      2. 1.3.2. Bean标签的范围配置
      3. 1.3.3. Bean 的声明周期配置
      4. 1.3.4. Bean实例化的三种方式
      5. 1.3.5. Bean的依赖注入分析
      6. 1.3.6. 依赖注入的概念
      7. 1.3.7. 依赖注入的方式
      8. 1.3.8. Bean依赖注入的数据类型
      9. 1.3.9. 引用其他配置文件(分模块开发)
    4. 1.4. Spring相关API
      1. 1.4.1. ApplicationContext 的继承体系
      2. 1.4.2. getBean 方法的使用
    5. 1.5. Spring配置数据源(连接池)
      1. 1.5.1. 数据源的作用
      2. 1.5.2. 数据源的配置文件
      3. 1.5.3. Spring配置数据源
      4. 1.5.4. Jdbc配置文件的抽取
    6. 1.6. Spring 注解开发
      1. 1.6.1. Spring原始注解
      2. 1.6.2. 注解详解
      3. 1.6.3. 注入
      4. 1.6.4. Spring 新注解
    7. 1.7. AOP
      1. 1.7.1. AOP 的作用和优势
    8. 1.8. AOP的底层实现
      1. 1.8.1. 常用的动态代理技术
    9. 1.9. AOP的相关概念
    10. 1.10. 基于XML的AOP开发
      1. 1.10.1. 切点表达式的写法
      2. 1.10.2. 通知的类型
    11. 1.11. 基于注解的AOP开发
    12. 1.12. Spring集成Web开发环境
      1. 1.12.1. spring 提供的监听器
    13. 1.13. SpringMVC
      1. 1.13.1. springMVC的组件解析
      2. 1.13.2. springMVC的XML文件解析
      3. 1.13.3. 数据响应
      4. 1.13.4. 获取请求数据
      5. 1.13.5. 文件上传
    14. 1.14. SSM框架整合
Spring

Spring

spring简介

spring是什么

spring是分层的javaSE/EE 应用full-stack(全栈)轻量级开源框架,以ioC(Inverse Of Control: 反转控制) 和 AOP(Aspect Oriented Programming: 面向切面编程) 为核心。提供了展现层SpringMVC 和持久层 SpringJDBCTemplate 以及业务层事务管理等众多的企业级应用技术。

spring的优势

  • 方便解耦,简化开发
    通过Spring提供的ioC容器,可以将对象间的依赖关系交由Spring进行控制,避免了硬编码所造成的过度耦合。用户也不必为单例模式类、属性文件解析等这些很底层的需求编写代码,可以专注于上层的应用。
  • AOP编程的支持
    通过Spring 的AOP功能,方便进行面向切面的编程
  • 声明式事务的支持
  • 方便程序的测试
  • 方便集成各种优秀的框架
  • 降低了javaEE API的使用难度

spring 的体系结构

Spring 快速入门

程序开发步骤

1、通过maven导入spring框架
2、实现需要的class以及相关的方法

  • 创建Bean

3、创建并配置xml文件(ApplicationContext.xml)
4、得到ApplicationContext对象,并且,通过app的getBean方法以及ID拿到我们需要的对象

Spring 配置文件

Bean 标签的基本配置

用于配置对象交由Spring来创建
默认情况下,它调用的是类中的无参构造函数,如果没有无参构造函数则不能创建成功

基本属性

ID:bean实例在Spring容器中的唯一标识
class:Bean的全限定名称

Bean标签的范围配置

scope:指对象的作用范围,取值如下:

  • singleton ==默认值,单例的==.每次getBean时得到的是同一个对象
  • prototype ==多例的==。每次getBean时得到的是不同的对象。
  • request WEB项目中,Spring 创建一个Bean对象,将对象存入到request域中
  • session WEB项目中,Spring创建一个Bean的对象,将对象存入session域中
  • global session WEB项目中,应用在portlet环境,如果没有Portlet环境那么gobalsession相当于session

singleton:javaBean 在加载spring文件,创建spring容器时创建
prototype:在getBean时才创建bean

Bean 的声明周期配置

init-method:指定类中的初始化方法名称
destroy-method:指定类中销毁方法的名称

Bean实例化的三种方式

  • 无参构造方法实例化

    1
    2
    <!--无参构造方法-->
    <bean id="userDao" class="com.xinyu.dao.impl.UserDaoImpl" scope="singleton" init-method="init" destroy-method="destroy"></bean>
  • 工厂静态方法实例化

    1
    2
    3
    4
    5
    6
    7
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="userDao" class="com.xinyu.factory.StaticFactory" factory-method="getUserDao" scope="singleton" ></bean>
    </beans>
  • 工厂实例方法实例化
1
2
3
4
<!--    工厂实例方法实例化-->
<bean id="factory" class="com.xinyu.factory.DynamicFactory"></bean>
<!-- 为了获得userDao这个对象,需要找factory这个对象,并调用getUserDao这个方法-->
<bean id="userDao" factory-bean="factory" factory-method="getUserDao"></bean>

Bean的依赖注入分析

若把UserService实例与UserDao实例都存在Spring容器中,当前的做法是在容器外部获得UserService实例和UserDao实例,然后在程序中进行结合。

有更好的实现方法:

依赖注入的概念

它是Spring框架核心IOC的具体实现
在编写程序时,通过控制反转,把对象的创建交给了Spring,但是代码中不可能出现没有依赖的情况。
IOC解耦只是降低了他们的依赖关系,但是不会消除。例如:业务层仍然会调用持久层的方法

那这种业务层和持久层的依赖关系,在使用Spring之后,就让Spring来维护了。简单来说,就是坐等框架把持久层对象传入业务层,而不用我们自己去获取。

依赖注入的方式

  • 构造方法注入

    1
    2
    3
    4
    5
    6
    7
    8
    9
    //需要在service 层,引入需要注入的成员   
    private UserDao userDao;

    // 用于构造方法注入
    public UserServiceImpl(UserDao userDao) {
    this.userDao = userDao;
    }
    public UserServiceImpl() {
    }
    1
    2
    3
    4
    5
    6
    7
    <!--无参构造方法-->
    <bean id="userDao" class="com.xinyu.dao.impl.UserDaoImpl" scope="singleton"></bean>
    <!-- 用于构造方法注入-->
    <bean id="userService" class="com.xinyu.service.impl.UserServiceImpl">

    <!-- constructor-arg 后面的name是需要构造的参数的名字。我们这里是private UserDao userDao中的名字。ref 引用了上面Bean 的id-->
    <constructor-arg name = "userDao" ref="userDao" ></constructor-arg>
  • set方法
    需要在UserService中引入一个set方法,得到一个UserDao。

    1
    2
    3
    4
    5
    6
    7
    <!--无参构造方法-->
    <bean id="userDao" class="com.xinyu.dao.impl.UserDaoImpl" scope="singleton"></bean>
    <!-- 生成UserService这个class-->
    <bean id="userService" class="com.xinyu.service.impl.UserServiceImpl">
    <!-- name代表的是Set后面的name,并且把setUserDao 中的UserDao变为userDao ref引用的是Bean的id userDao-->
    <property name="userDao" ref="userDao"></property>
    </bean>
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class UserServiceImpl implements UserService {
    //在这个class中私用成员,并且在xml中把它依赖注入。即通过spring,实现setUserDao这个功能
    private UserDao userDao;
    public void setUserDao(UserDao userDao){
    this.userDao = userDao;
    }
    public void save(){
    userDao.save();
    }
    }

简便版本;P命名空间注入。

1
2
3
4
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
//需要添加一个P命名空间。它如何得到呢,就是复制上面的xmlns然后,冒号P,并且把schema后的变为P
xmlns:p="http://www.springframework.org/schema/p"
1
2
<!--    p命名空间注入方式-->
<bean id="userService" class="com.xinyu.service.impl.UserServiceImpl" p:userDao-ref="userDao"></bean>

Bean依赖注入的数据类型

除了在Bean 里面注入对象的引用之外,普通数据类型、集合等都可以在容器中进行注入。
注入数据的三种数据类型

  • 普通数据类型

    1
    2
    3
    4
    5
    6
    7
    8
    //在UserDaoImpl内部
    int a;
    public int getA(){
    return a;
    }
    public void setA(int a){
    this.a = a;
    }
    1
    2
    3
    <bean id="userDao" class="com.xinyu.dao.impl.UserDaoImpl" scope="singleton">
    <property name="a" value="3"></property>
    </bean>
  • 引用数据类型(主要是Bean类型)

  • 集合数据类型

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <bean id="userDao" class="com.xinyu.dao.impl.UserDaoImpl" scope="singleton">
    <property name="a" value="3"></property>
    <property name="stringList">
    <list>
    <value>aasfa</value>
    <value>aasfa</value>
    <value>aasfa</value>
    </list>
    </property>
    <property name="properties">
    <props>
    <prop key="p1">ppt1</prop>
    <prop key="p2">ppt2</prop>
    </props>
    </property>
    </bean>

引用其他配置文件(分模块开发)

实际开发中,Spring的配置内容非常多,这就导致了Spring的配置很繁杂。所以可以将部分配置拆解到其他配置文件中,而在Spring 的主配置文件通过import标签进行加载。

1
<import resource = "applicationContext-xxx.xml"/>

Spring相关API

ApplicationContext 的继承体系

applicationContext:接口类型,代表应用上下文,可以通过其实例获取Spring容器中的Bean对象。

图中,紫色的是接口,绿色的浅色是抽象类,深色的绿色是两个实现。

  • ClassPathXmlApplicationContext
    它是从类的根路径下加载配置文件,推荐使用这种
  • FileSystemXmlApplicationContext
    它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置
  • AnnotationConfigApplicationContext
    当使用注解配置容器对象时,需要使用此类来创建spring容器,它用来读取注解。

getBean 方法的使用

1、传入字符串,即xml中Bean 的id,来得到对象。
2、传入某个的class 的字面常量,即类名.class

Spring配置数据源(连接池)

数据源的作用

数据源是提高程序性能出现的
事先实例化数据源,初始化部分连接资源
使用连接资源时从数据源获取
使用完毕后,将连接资源归还给数据源

数据源的配置文件

1
2
3
4
5
6
7
8
9
10
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/girls
jdbc.username=root
jdbc.password=172383
# 初始化连接数量
initialSize=5
# 最大连接数
maxActive=10
# 最大超时时间
maxWait=3000

Spring配置数据源

将DataSource 的创建权交给Spring

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/girls"></property>
<property name="user" value="root"></property>
<property name="password" value="172383"></property>
</bean>
</beans>

Jdbc配置文件的抽取

上面的代码可知,Spring中把数据库连接的方式包括了。所以需要把数据库的配置方式抽取出来,让spring来加载这个properties文件
步骤:
1、引入context命名空间和约束路径:

  • 命名空间

    1
    xmlns:context="http://www.springframework.org/schema/context"
  • 约束路径

    1
    2
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 加载外部的properties文件-->
    <context:property-placeholder location="classpath:c3p0.properties"/>

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="${jdbc.driver}"></property>
    <property name="jdbcUrl" value="${jdbc.url}"></property>
    <property name="user" value="${jdbc.username}"></property>
    <property name="password" value="${jdbc.password}"></property>
    </bean>

    </beans>

Spring 注解开发

Spring是轻代码而重配置的框架,配置比较繁重,影响开发速率,所以注解开发是一种趋势,注解代替xml配置文件可以简化配置,提高开发效率。

Spring原始注解

Spring的原始注解主要是替代的配置
image-20201029160435123

使用注解开发时,需要在applicationContext.xml中配置组件扫描,作用是指定哪个包及其子包下的Bean需要进行扫描以便识别使用注解配置的类,字段和方法。

1
<context:component-scan base-package="com.xinyu"/>

注解详解

@Component(“id”) 用于创建Bean,每个层都能用,放入spring容器中
@Controller(“id”) 用于Web层创建Bean
@Service(“id”) 用于service层
@Repository(“id”) 用于dao层

注入

@Autowired:按照数据类型从Spring容器中进行匹配注入

@Qualifier:按照id值从容器中进行匹配。

注意,@Qualifier 必须搭配@Autowired一起使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//@Component("userService")
@Service("userService")
public class userServiceImpl implements UserService {

// 自动注入.即框架通过setUserDao方法使得UserService的私有成员userDao初始化为spring创建的UserDao的对象
// setUserDao这个方法在使用注解时,可以不写。
@Autowired


//这句话也可以不写,这个时候,spring就按照数据类型从spring容器中进行匹配
// 写上就是按照id值从容器中进行匹配。
@Qualifier("userDao")
private UserDao userDao;
// public void setUserDao(UserDao userDao){
// this.userDao = userDao;
// }
public void save(){
userDao.save();
}

}

@Resource(name = “id”)
这个注入相当于@Autowired+@Qualifier

普通字符串的注入

@Value(string)

1
2
@Value("${jdbc.driver}")
private String driver;

@Scope(“singleton”)&@Scope(“prototype”)
控制产生单例或者多个Bean

Spring 新注解

原始注解对于非自定义的bean等无法进行注解,所以无法全部代替xml配置文件。所以需要新注解

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
/*
本文件是用来代替applicationContext.xml文件的。
*/
//该标志是Spring的核心配置类
@Configuration
//组件扫描
@ComponentScan("com.xinyu")

//加载property文件
@PropertySource("classpath:jdbc.properties")
public class springConfiguration {
@Value("${jdbc.driver}")
private String driver;

@Value("${jdbc.url}")
private String url;

@Value("${jdbc.username}")
private String username;

@Value("${jdbc.password}")
private String password;

// spring 会将当前方法的返回值以指定名称存储到spring容器中
@Bean("dataSource")
public DataSource getDataSource() throws Exception{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass(driver);
dataSource.setJdbcUrl(url);
dataSource.setUser(username);
dataSource.setPassword(password);
return dataSource;
}

//之后再使用的时候,就不是加载xml文件的方式来得到bean了。而是加载这个class
public class serviceController {
public static void main(String[] args) {
// 用于加载xml文件的
// ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
ApplicationContext app = new AnnotationConfigApplicationContext(springConfiguration.class);
UserService userService = app.getBean(UserService.class);
userService.save();
}
}

AOP

AOP(Aspect Oriented Programming) 意思为面向切面编程,是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。

AOP 的作用和优势

作用:在程序运行期间,在不修改源码的情况下对方法进行功能增强。

优势:减少重复代码,提高开发效率,并且便于维护。

实现原理:当多个函数都会去调用另外一个函数时,传统选择是使用每个函数来引用。但是这样使得函数间耦合了。所以我们选择在内存中运行时把他们结合到一起,而不是引用他们。那么如何在内存中使得他们运行呢,就是使用配置文件。

AOP的底层实现

AOP的底层是通过Spring提供的动态代理技术实现的。在运行期间,Spring通过动态代理技术动态生成代理对象,代理对象执行时进行增强功能的介入。再去调用目标对象的方法,从而完成功能的增强。

常用的动态代理技术

  • JDK代理:基于接口的动态代理技术
  • cglib代理:基于父类的动态代理技术

AOP的相关概念

Target:被代理的目标对象
Proxy:一个类被AOP织入 增强后,产生的一个结果代理类
JoinPoint:连接点,指的是那些被拦截到的点。在Spring 中这些点指的是方法。因为spring只支持方法类型的连接点。
PointCut:切入点。指我们要对哪些Joinpoint进行拦截的定义。即,已经被增强的点,为切入点。
Advice:通知/增强。是指拦截到Joinpoint之后要做的事情。
Aspect:切面。是指切入点和通知的结合
Weaving:织入。

基于XML的AOP开发

1、导入AOP相关坐标
2、创建目标切面和目标类
3、创建切面类(内部有增强方法)
4、将目标类和切面类的对象创建权交给spring
5、在applicationContext.xml中配置织入关系
6、测试代码

配置文件

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
<?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:aop = "http://www.springframework.org/schema/aop"

xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

<!-- 目标对象-->
<bean id="target" class="com.xinyu.aop.target"></bean>
<!-- 切面对象-->
<bean id="myAspect" class="com.xinyu.aop.myAspect"></bean>

<!-- 配置织入:告诉spring框架,告诉哪些切点需要增强-->
<aop:config>
<!-- 声明切面-->
<aop:aspect ref="myAspect">
<!-- 切面:切点+ 通知
aop:before:前置增强,method 选择哪个方法作为前置增强
pointcut:切点,即要插入前置或者后置增强的方法是哪个

-->
<aop:before method="before" pointcut="execution(public void com.xinyu.aop.target.save())"></aop:before>

</aop:aspect>
</aop:config>
</beans>

切点表达式的写法

excution([修饰符]返回值类型 包名.类名.方法名(参数))

  • 访问修饰符可以省略

  • 返回值类型、包名、类名、方法名可以使用* 代表任意

  • 包名与类名之间一个.代表当前包下的类,两个.表示当前包及其子包下的类

  • 参数列表可以使用两个点.表示任意个数,任意类型的参数列表

第二个:Target类下的任意方法,参数任意
第三个:任意返回值,aop包下的任意类的任意方法,参数任意
第四个:aop及其子包下的任意类的任意方法

通知的类型

基于注解的AOP开发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?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"
xmlns:aop = "http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

<context:component-scan base-package="com.xinyu.anno"></context:component-scan>


<!-- aop自动代理-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
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
@Component("myAspect")

//代表这个类是一个切面类
@Aspect
public class myAspect {

//配置前置通知
@Before("execution(* com.xinyu.anno.*.*(..))")
public void before() {
System.out.println("触发");
}

//配置后置通知
@AfterReturning("execution(* com.xinyu.anno.*.*(..))")
public void after() {
System.out.println("结束");
}
}



@Component("target")
public class target implements targetInterface {
public void save(){
System.out.println("saving...");
}
}

Spring集成Web开发环境

在servlet的doGet之类的代码中,如果每次都去加载spring的xml文件,就会很麻烦。我们只需要加载一次xml文件,从一个容器中来获取需要的类

我们可以使用ServletContextListener监听Web应用的启动。我们可以在Web应用启动的时间,就加载spring的配置文件。创建应用上下文对象ApplicationContext,在其存储到最大的域,servletContext域中。这样就可以在任意位置中获取应用上下文ApplicationContext对象了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class ContextLoaderListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {

ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");

// 将spring的应用上下文对象存储到servletContext域中.
ServletContext servletContext = servletContextEvent.getServletContext();

servletContext.setAttribute("app",app);
System.out.println("spring 容器创建完毕");
}

@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {

}
}
1
2
3
4
<!--    配置监听器-->
<listener>
<listener-class>com.xinyu.listener.ContextLoaderListener</listener-class>
</listener>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//servlet中使用
public class UserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 找spring容器,要service对象.然后调用它的save方法.实现对网页的处理
// ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");

// 上面的是没有监听器的处理方法.配置监听器之后.我们可以使用监听器初始化我们的xml文件来得到我们需要的Bean
ServletContext servletContext = this.getServletContext();
ApplicationContext app = (ApplicationContext) servletContext.getAttribute("app");

UserService userService = app.getBean(UserService.class);
userService.save();
}
}

可以看到,我们在没有访问网页的情况下,监听器已经加载了xml文件,spring容器创建完毕了。这样在servlet中,我们就可以通过servletContext来得ApplicationContext

优化:上面的代码有一些耦合的地方,我们需要进行一些改进。

1、在listener中,我们直接把applicationContext.xml文件名写了上去,导致耦合。我们应该把它放入WEB-INF的全局变量中,通过代码获得文件名称来加载文件。

2、我们直接把加载的applicationContext.xml 叫做app。但是,它也可以不叫app。所以也需要我们优化。

完整版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class ContextLoaderListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
ServletContext servletContext = servletContextEvent.getServletContext();
String appConfig = servletContext.getInitParameter("contextConfigLocation");

ApplicationContext app = new ClassPathXmlApplicationContext(appConfig);

// 将spring的应用上下文对象存储到servletContext域中.

servletContext.setAttribute("app",app);
System.out.println("spring 容器创建完毕");
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {

}
}
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
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">

<servlet>
<servlet-name>UserServlet</servlet-name>
<servlet-class>com.xinyu.web.UserServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UserServlet</servlet-name>
<url-pattern>/userServlet</url-pattern>
</servlet-mapping>

<!-- 配置监听器-->
<listener>
<listener-class>com.xinyu.listener.ContextLoaderListener</listener-class>
</listener>

<!-- 全局初始化参数-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>applicationContext.xml</param-value>
</context-param>
</web-app>

Utils

1
2
3
4
5
public class WebApplicationContextUtils {
public static ApplicationContext getApplicationContext(ServletContext servletContext){
return (ApplicationContext) servletContext.getAttribute("app");
}
}

servlet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class UserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 找spring容器,要service对象.然后调用它的save方法.实现对网页的处理
// ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");

// 上面的是没有监听器的处理方法.配置监听器之后.我们可以使用监听器来得到我们需要的Bean
ServletContext servletContext = this.getServletContext();

// 通过Utils的使用,我们可以避免使用get("app")这个东西.这样避免了耦合.
// ApplicationContext app = (ApplicationContext) servletContext.getAttribute("app");

ApplicationContext app =WebApplicationContextUtils.getApplicationContext(servletContext);
UserService userService = app.getBean(UserService.class);
userService.save();
}
}

spring 提供的监听器

spring提供的监听器:ContextLoaderListener对上诉功能的封装。该监听器内部加载spring配置文件,创建上下文对象。并存储到ServletContext域中。提供一个客户端工具WebApplicationContextUtils供使用者获取应用上下文对象。

步骤:

  • 在web.xml中配置ContextLoaderListener监听器(导入spring-web坐标)
  • 使用WebApplicationContextUtils获取应用上下文对象ApplicationContext

1、web-xml中导入spring自带的ContextLoaderListener

1
2
3
4
5
6
7
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>

在userServlet中调用

1
2
3
4
ApplicationContext app = WebApplicationContextUtils.getWebApplicationContext(servletContext);

UserService userService = app.getBean(UserService.class);
userService.save();

SpringMVC

SpringMVC是一种基于JAVA实现的MVC设计模型的请求驱动类型的轻量级Web框架,属于SpringFrameWork的后续产品。已经融合在Spring Web Flow中了。

我们的前端控制器就是SpringMVC。
使用过程:

  • 1、导入SpringMVCjar包
1
2
3
4
5
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
  • 2、配置servlet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!--    配置spring-mvc的前端控制器-->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 告诉这个控制器,spring-mvc.xml文件在哪。这样,下面的监听器就可以扫描并加载了-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>

<!-- tomcat 启动时就创建对象-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
  • 3、编写Controller(Web层的javaBean)
  • 4、将Controller使用注解配置到spring容器中。
1
2
3
4
5
6
7
8
9
10
11
12
13
/*
这里使用了注解的方法来进行配置。Controller是web层面的创建Bean
@RequestMapping 是和一个网址后缀匹配。返回的字符串是请求转发的网页资源
*/
@Controller
public class UserController {

@RequestMapping("/save")
public String save(){
System.out.println("userController running");
return "success.jsp";
}
}
  • 5、配置spring-mvc.xml文档
1
2
3
4
5
6
7
8
9
10
11
<?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 http://www.springframework.org/schema/context/spring-context.xsd">

<!-- 组件扫描-->
<context:component-scan base-package="com.xinyu.controller"></context:component-scan>

</beans>

注意要把这个xml文档加载。需要在WEB-INF文件下的web.xml中进行配置。具体过程看上图。

注意:可能在maven中导入坐标之后,项目的artifacts的lib中没有jar包,需要我们手动添加一下。

springMVC的组件解析

==RequestMapping()==

用于建立URL和处理请求方法(Controller)直接的对应关系

在class上进行注解的话,这就是URL的第一层访问路径。如果不写的话,我们访问方法的路径就是从根目录开始。

在方法上进行注解。这用于我们具体需要访问的某个资源。和class上的注解同时使用来分开不同的访问资源。

但是当我们使用这样的方法的时候,会发现,网页报错

这是因为,我们返回的字符串是success.jsp,它默认为我们当前路径下的地址。

所以我们需要返回/success.jsp 这相当于我们从web目录下寻找资源。

注解具体的参数

  • value=”/xxx” 单独写URL时,这个value可以省略。
  • method=RequestMethod.GET/POST 设定我们要访问的方法必须是GET/POST

注意,我们使用post请求的情况是:用get请求加载了登录的界面了。当我们点击登录的时候,发送post请求,然后写一个方法来接受这个post请求。网页初始的请求都是get请求,我们不能直接访问到我们所写的post请求处理的方法的。

  • params = {“username”} 代表了我们访问这个网页的时候,必须带有username这个参数。

springMVC的XML文件解析

除了配置controller的组件扫描,我们还可以配置内部资源的视图解析器

数据响应

1、页面跳转

  • 直接返回字符串

  • 通过ModelAndView对象返回

2、回写数据

  • 直接返回字符串

    当我们想把一个类response到网页上是json格式的字符串时,我们需要在maven中导入jackson相关的坐标

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.12.0</version>
    </dependency>
    <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.12.0</version>
    </dependency>
    <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.12.0</version>
    </dependency>

    然后,在controller中调用,使得把这个类转化为string。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @RequestMapping("/modelAndView5")
    @ResponseBody
    public String write3() throws IOException {
    user user = new user();
    user.setAge(21);
    user.setName("儿砸");
    user.setGender("girl");
    // jackson 关系映射
    ObjectMapper objectMapper = new ObjectMapper();
    String json = objectMapper.writeValueAsString(user);
    return json;
    }
  • 返回对象集合

但是这个是比较麻烦的。我们每次返回json都需要去生成。所以使用在mvc.xml中配置RequestMappingHandlerAdapter,给它的property传入MappingJackson2HttpMessageConverter。这样,我们可以直接返回一个类,spring会把它转为string,传入web。并且它的默认字符集是utf-8。

1
2
3
4
5
6
7
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
</list>
</property>
</bean>
1
2
3
4
5
6
7
8
9
@RequestMapping("/modelAndView6")
@ResponseBody
public user write4(){
user user = new user();
user.setAge(21);
user.setName("儿砸");
user.setGender("girl");
return user;
}

但是这样还是有一点麻烦的。所以springMVC提供了注解驱动。

获取请求数据

1、获得基本请求参数
Controller中的业务方法的参数名称,要与请求参数的name一致,参数值会自动匹配

1
2
3
4
5
6
@RequestMapping("/getdata1")
@ResponseBody
public void getAll(String username,int age)throws IOException{
System.out.println(username);
System.out.println(age);
}

2、获得POJO(javaBean)类型参数
需要我们请求的参数与javaBean中参数名称对应

1
2
3
4
5
@RequestMapping("/getdata2")
@ResponseBody
public void getUser(user user) throws IOException{
System.out.println(user.getAge()+" "+user.getName());
}

3、获取数组类型参数

1
2
3
4
5
6
7
@RequestMapping("/getdata3")
@ResponseBody
public void getArray(String[] names)throws IOException{
for (String name:names){
System.out.println(name);
}
}

网页上回传的数据名称都为names。

4、获取集合类型的参数

获得集合参数时,需要把集合参数,封装到jopo中,作为javaBean的参数.提交页面时,使用post方式。

静态资源的获取:通过在spring-mvc.xml中加入<mvc:default-servlet-handler/>。使得框架找不到的静态资源,让tomcat找

请求数据乱码问题

post表单中。我们提交中文会出现乱码问题。

解决方法: 在web.xml中配置一个全局过滤的filter

1
2
3
4
5
6
7
8
9
10
11
12
13
<!--    配置一个全局过滤的filter.解决post请求乱码问题-->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

参数绑定注解

用于当我们网页上返回的参数名称和接受中不一样时,我们把它们做映射。

1
2
3
4
5
6
@RequestMapping("/getdata5")
@ResponseBody
public void getname(@RequestParam(value = "name") String username) throws IOException{
System.out.println(username);
}
}

@RequestParam(value = "name",required = false) 不返回数据也不会报错.若再添加defaultValue="xinyu",则,不输入数据,返回默认值-xinyu

获取Restful风格的参数

Restful是一种软件的架构风格。而不是标准,只是提供了一组设计原则和约束条件。主要用于客户端和服务端交互类的软件。基于这种风格设计的软件更简洁,更有层次。

Restful风格的请求是使用“url+请求方式”表示一次请求的目的,HTTP协议里面四个表示操作方式的动词如下:

  • GET:用于获取资源
  • POST:用于新建资源
  • PUT:用于更新资源
  • DELETE:用于删除资源

自定义类型转换器

springMVC已经提供了一些常用的类型转换器,但是不是所有的数据类型都提供了转换器。没有提供的需要我们自己写自定义转换器。例如:日期类型的数据需要我们自己写。

步骤
1、定义转换器类实现Converter接口
2、在配置文件中,声明转换器
3、在<annotation-driven中引用转换器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//定义接口
public class dateConverter implements Converter<String, Date> {
@Override
public Date convert(String dateStr) {
// 将日期字符串,转换为真正的日期对象

SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Date date = null;
try {
date = format.parse(dateStr);
}
catch (ParseException e){
e.printStackTrace();
}
return date;
}
}
1
2
3
4
5
6
7
8
9
10
11
<!--    声明日期转换器-->
<bean id="ConversionService1" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="com.xinyu.converter.dateConverter"></bean>
</list>
</property>
</bean>


<mvc:annotation-driven conversion-service="ConversionService1"/>

获取Servlet原生的API

springMVC获取请求数据

1
2
3
4
5
6
//    获取请求头数据
@RequestMapping("/getdata8")
@ResponseBody
public void get9(@RequestHeader(value = "User-Agent") String user_agent)throws IOException{
System.out.println(user_agent);
}

文件上传

SSM框架整合

文章作者: Dr-xinyu
文章链接: https://dr-xinyu.github.io/2020/10/27/JavaSpring/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 心雨
打赏
  • 微信
  • 支付寶