SSM框架

SSM

Maven是什么?

​ Maven 是Apache旗下的一个项目,这个项目是纯java开发,主要用来管理Java项目

​ 目前我们使用的第三方jar包越来越多,而伴随jar包的增加,项目的体积会越来越大,使用maven可以减少项目体积

​ 随着我们使用的jar包越来越多,我们需要上网到处寻找需要的jar包以及版本,非常麻烦,而maven提供一中央仓库,里面有所有常用jar包

​ Maven可以管理项目的生命周期:编码、编译、测试、运行、打包、部署

​ Maven的依赖管理:

​ 1、jar包冲突

​ 2、jar包之间互相依赖

​ 3、jar包体积过大

​ Maven的仓库有三种:

​ 1、中央远程库

​ 2、私服

​ 3、本地仓库

​ 当我们在项目中添加依赖的时候,maven会先去本地仓库寻找,在本地仓库找到则直接引用,如果没有找到则去私服寻找,如果私服也找不到则去中央仓库寻找,当在中央仓库找到之后会先下载到本地仓库之中,然后进行引用

​ Maven根据坐标以及版本号来确定需要使用的依赖

​ GroupID:公司名称(组织的唯一标识)

​ AritfactID:项目唯一标识符

​ Version:版本号

框架

什么是框架

​ 框架是指一些能完成特定功能的半成品(实际上就是别人写好的代码),所有的框架都是傻的,因为框架自身什么都做不了,他只是个半成品而已,想让框架发挥作用需要使用者去配置

Spring(春天)

​ spring是程序员的春天,因为spring的出现解决了很多之前程序中出现的问题(耦合与内聚)

Spring配置文件
-pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.ishangu</groupId>
    <artifactId>SpringDI</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.9</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.3.9</version>
        </dependency>
    </dependencies>
</project>
-application.xml
<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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans  
                           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                           http://www.springframework.org/schema/context 
                           http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <bean id="dog" class="com.ishangu.Dog">
        <property name="id" value="1"></property>
        <property name="name" value="小黃"></property>
        <property name="color" value="綠色"></property>
    </bean>

    <bean id="man" class="com.ishangu.Man">
        <!-- 引用上面的bean对象 -->
        <property name="dog" ref="dog"></property>
    </bean>

    <bean id="k" class="com.ishangu.Kid" autowire="byName" />
    
    <bean id="dog" class="com.ishangu.Dog" p:id="1" p:name="小黃" p:color="绿色">
    </bean>

    <bean id="man" class="com.ishangu.Man" p:dog-ref="dog">
    </bean>
    
    <bean id="c" class="com.ishangu.Cat" lazy-init="true" scope="prototype">
        <!-- 指定通过有参构造创建对象,i是构造方法中形参的名称  value是赋给形参的值  -->
        <constructor-arg name="i" value="5" /> 
    </bean>


    <bean id="c2" class="com.ishangu.Cat">
        <!-- 指定通过有参构造创建对象,0是形参的下标  value是赋给形参的值  -->
        <constructor-arg index="0" value="100" />
    </bean>

    <!-- 静态工厂实例化 -->
    <bean id="a" class="com.ishangu.AFactory" factory-method="getA"/>
    
    <!-- 实例工厂实例化-->
    <bean id="bf" class="com.ishangu.BFactory"/>
    <bean id="b" factory-bean="bf" factory-method="getB" />

    <bean id="hello" class="com.ishangu.Hello" init-method="init" scope="prototype" destroy-method="close" />
</beans>
spring的主要功能

​ 1、使用spring可以轻松让代码解耦

​ 2、spring可以帮我们控制数据库的事务

​ 3、spring是一个非侵入式的轻量级框架

​ 4、目前市面上所有主流框架都能被spring集成

​ 5、spring自身提供了JavaEE一站式开发(一条龙服务)

spring的常用术语

​ 1、应用程序:一般是指我们的项目

​ 2、框架:是别人写好的项目我们直接引用

​ 3、非侵入式:是指在替换框架的时候,不需要修改源代码

​ 4、轻量级:轻量级的框架依赖的东西较少,占用资源较少,部署也比较简单,一般非侵入式都是轻量级框架

​ 5、容器:是指装对象的一个东西

​ 6、bean:就是Java中类的实例化对象

spring的版本与jdk的关系

​ 5.x:支持jdk1.8

​ 4.x:支持jdk1.8

​ 3.x:支持jdk1.5~1.7

​ 2.x:支持jdk1.4

spring中的常见组件

​ SpringContext:上下文支持

​ SpringAOP:AOP切面编程(封装了动态代理)

​ SpringBeans:IOC工厂(封装了工厂,单例等)

​ SpringCore:核心

​ SpringTest:封装了测试相关的内容

​ SpringData:封装了数据相关的内容

​ SpringJDBC:封装了JDBC

IOC:控制反转

​ 是指创建对象的控制权被反转了,以前都是我们手动在代码中通过new关键字获取对象,而现在对象被Spring容器创建以及管理,当我们需要使用对象的时候直接从容器中获取即可

Spring实例化bean对象的时机

​ Spring默认在容器启动的时候就加载所有的对象,我们可以指定bean的lazy-init属性,来改变实例化时机

lazy-init

​ true:表示什么时候使用对象什么时候加载对象

​ false:表示当容器启动立即加载对象

​ default:相当于false

bean对象的作用域

​ Spring管理的bean默认都是单例的,我们可以通过scope属性来控制对象是否单例

scope

​ prototype:多例每次从容器中获取对象的时候都会创建一个新的对象

​ singleton:单例,容器中的对象永远只有一个实例(默认)

​ request:每次请求都会创建一个新的对象

​ session:每次会话使用的都是同一个对象

​ globalSession:全局session(分布式项目中的session)

<bean id="c" class="com.ishangu.Cat" lazy-init="true" scope="prototype">
    <constructor-arg name="i" value="5"/>
</bean>
Spring实例化对象的方式

​ 1、通过无参构造实例化对象

<bean id="dog" class="com.ishangu.Dog">
    <property name="id" value="1"></property>
    <property name="name" value="小黃"></property>
    <property name="color" value="綠色"></property>
</bean>
<bean id="man" class="com.ishangu.Man">
    <!-- 引用上面的bean对象 -->
    <property name="dog" ref="dog"></property>
</bean>

​ 2、通过有参构造实例化对象

<bean id="c" class="com.ishangu.Cat" lazy-init="true" scope="prototype">
    <!-- 指定通过有参构造创建对象,i是构造方法中形参的名称  value是赋给形参的值  -->
    <constructor-arg name="i" value="5" /> 
</bean>

<bean id="c2" class="com.ishangu.Cat">
    <!-- 指定通过有参构造创建对象,0是形参的下标  value是赋给形参的值  -->
    <constructor-arg index="0" value="100" />
</bean>

​ 3、静态工厂实例化

package com.ishangu.factory;

import com.ishangu.User;

public class StaticFactory {
    public static User getUserBean(){
        return new User();
    }
}
<!-- 静态工厂实例化 -->
<bean id="a" class="com.ishangu.StaticFactory" factory-method="getUserBean"/>

​ 4、实例工厂实例化

package com.ishangu.factory;

import com.ishangu.User;

public class DynamicFactory {
    public User getUserBean(){
        return new User();
    }
}
<!-- 实例工厂实例化-->
<bean id="bf" class="com.ishangu.DynamicFactory"/>
<bean id="b" factory-bean="bf" factory-method="getUserBean" />

​ 5、通过实现FactoryBean接口来实例化对象(一般由第三方框架使用)

Spring管理对象的声明周期

​ 我们可以通过destroy-method、init-method属性来指定在实例化bean对象的时候调用什么方法以及销毁对象的时候调用什么方法(需要注意的是多例的对象Spring只负责创建,不负责销毁)

​ 初始化容器---->通过反射创建对象---->调用初始化方法---->关闭容器的时候调用销毁的方法

package com.ishangu;

public class Hello {

    public void init(){
        System.out.println("正在初始化");
    }

    public void close(){
        System.out.println("正在关闭");
    }

    public void sayHello(String i){
        System.out.println(i+"hello");
    }
}
<bean id="hello" class="com.ishangu.Hello" init-method="init" destroy-method="close"></bean>
DI:依赖注入

​ 所谓的依赖注入是指,在创建对象的时候,给对象的属性赋值

依赖注入的实现方式

​ 1、接口注入(几乎不用)

​ 2、set注入

-通过调用set方法来完成注入,需要注意的是,name的值需要与set方法的名称对应
(1)通过ref引用外部bean标签
(2)内部bean标签
(3)通过p命名空间注入
<bean id="user" class="com.ishangu.User" p:name="小明"></bean>
<bean id="person" class="com.ishangu.model.Person">
    <property name="name" value="小明"></property>
</bean>
<bean id="user" class="com.ishangu.User" p:name="小明" p:person-ref="person"></bean>

​ 3、构造注入

​ 4、字段注入(最常用的方式)

-@Autowired,可以写在字段上以及方法上
(1)写在字段上,要求字段的名称需要与bean的id保持一致,如果不保持一致,相同类型的bean数量在两个以上就会报错
(2)写在方法上,要求形参的名称需要与bean的id保持一致,如果不保持一致,相同类型的bean数量在两个以上就会报错
(3)匹配规则,会先按照类型去寻找,如果找到多个相同类型的bean则根据id进行匹配,匹配成功则注入,匹配失败则抛出异常
-@Qualifier
用来配合@Autowired来使用,专门用来解决容器中有多个相同类型的bean并且ID与属性名都不相同的情况下,使用@Qualifier可以将指定的bean对象注入到字段之中
-@Autowired
注解默认必须要从IOC容器中获取对象,如果获取不到就会抛出异常,如果我们需要的bean不是必须的情况下可以指定其属性required=false来避免抛出异常,但是使用这个方式可能会造成IOC容器中获取不到bean对象还不报错,所以尽量慎用
-@Resource
用处与@Autowired一致,都是从IOC容器中获取对象注入到属性中,但是其自身就有指定ID的功能,所以不需要@Qualifier来配合,而且由于注解不属于Spring所以哪怕以后将Spring框架替换掉也不影响代码的运行
匹配规则,先按照名称寻找bean对象,如果找不到则根据类型寻找,当找到多个类型的时候会抛出异常
@Autowired
private Dog dog;
装配方式

​ 注入是指所有的数据类型,而装配单指引用数据类型

-xml装配(手动)
就是指对象之间的依赖关系是我们在xml中手动去维护
-xml装配(自动)
对象之间的依赖关系由容器在运行的时候自动去维护
-注解装配
是指对象之间的关系是我们使用Autowired或者Resource注解在代码中维护的
-以后的使用
1+3

​ xml装配(自动)

private Cat cat;
private Pig pig;

@Override
public String toString() {
    return "Kid [dog=" + dog + ", cat=" + cat + ", pig=" + pig + "]";
}

public Kid(Cat cat, Pig pig) {
    super();
    this.cat = cat;
    this.pig = pig;
}
<bean id="cat" class="com.ishangu.Cat"></bean>
<bean id="pig" class="com.ishangu.Pig"></bean>
配置list、map、properties
<bean id="user" class="com.ishangu.User">
    <property name="name" value="小明"/>
    <property name="person" ref="person"></property>
    <property name="list">
        <list>
            <value>aaa</value>
            <value>bbb</value>
            <value>ccc</value>
        </list>
    </property>
    <property name="map">
        <map>
            <entry key="1" value-ref="person"></entry>
            <entry key="2" value-ref="person"></entry>
            <entry key="3" value-ref="person"></entry>
        </map>
    </property>
    <property name="properties">
        <props>
            <prop key="a">1</prop>
            <prop key="b">2</prop>
            <prop key="c">3</prop>
        </props>
    </property>
</bean>
<bean id="person" class="com.ishangu.model.Person">
    <property name="name" value="黄种人"/>
</bean>
导入其他的配置文件
<import resource="applicationContext.xml"/>
<import resource="applicationContext-user.xml"/>
数据源(连接池)
<!--加载外部properties文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="${jdbc.driver}"/>
    <property name="jdbcUrl" value="${jdbc.url}"/>
    <property name="user" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
</bean>
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost/aaa
jdbc.username=root
jdbc.password=123456
Sring原始注解
注解说明
@Component使用在类上用于实例化对象
@Controller使用在web层类上用于实例化Bean
@Service使用在Service层类上用于实例化Bean
@Respository使用在dao层类上用于实例化Bean
@Autowired使用在字段上用于根据类型依赖注入
@Qualifier结合@Autowired一起使用用于根据名称进行依赖注入
@Resource相当于@Autowired+@Qualifier,按照名称进行注入
@Value注入普通属性
@Scope标注Bean的作用范围
@PostConstruct使用在方法上标注该方法是Bean的初始化方法
@PreDestroy使用在方法上标注该方法是Bean的销毁方法
Spring新注解
注解说明
@Configuration用于指定当前类是一个 Spring 配置类,当创建容器时会从该类上加载注解
@ComponentScan用于指定 Spring 在初始化容器时要扫描的包。作用和在 Spring 的 xml 配置文件中的<context:component-scan base-package=“com.itheima”/>一样
@Bean使用在方法上,标注将该方法的返回值存储到 Spring 容器中
@PropertySource用于加载.properties 文件中的配置
@Import用于导入其他配置类
AOP

​ (基于动态代理)面向(横)切面编程

为什么需要AOP
-虽然动态代理也能实现增强,但是动态代理最小代理单元是类,而AOP增强的最小单元是方法
-以后我们的代码中可能涉及多种业务,例如日志处理,事务管理,权限管理等很多操作,这些操作有很多都是重复的,使用AOP可以将重复的代码抽离出来,通过织入的方式对原有代码进行增强,并不影响源代码
-Spring的事务管理功能非常强悍,并且支持主流的所有ORM框架,而Spring的事务管理就是基于SpringJDBC以及AOP来实现的
AOP中的术语
-切面
由通知+切入点组成
-通知
是指在什么时间进行切入(在方法之前切入,还是方法执行之后切入)
-切入点
是指需要哪些类,以及哪些方法进行增强
-增强
需要放入切入点的代码
-织入
将增强放入到切面中的过程,而这个过程由Spring自动完成
-连接点
将前后置增强连接到一起的一个pointcut
AOP基于动态代理实现
  • JDK动态代理

    • JDK动态代理要求,被代理的类必须实现某个接口,因为生成的代理类会自动实现对应的接口
  • cglib动态代理

    • cglib动态代理要求,被代理的类不能是final修饰的,因为生成的代理类会自动继承被代理类
AOP配置
<?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"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans  
                           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                           http://www.springframework.org/schema/context 
                           http://www.springframework.org/schema/context/spring-context-3.0.xsd
                           http://www.springframework.org/schema/aop
                           http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
    <context:component-scan base-package="com.ishangu" />
    <!-- 1、把被增强的内容,放入到IOC容器中 -->
    <bean id="a" class="com.ishangu.aop.Aop" />

    <aop:config>
        <!-- 配置切入点 -->
        <aop:pointcut expression="execution(public * com.ishangu.*.*.*(..))" id="poi"/>
        <!-- 配置切面 -->
        <aop:aspect ref="a">
            <!-- 配置前置增强 -->
            <aop:before method="open" pointcut-ref="poi"/>
            <!-- 配置后置增强,只有当方法正常结束之后才会执行 -->
            <aop:after-returning method="close" pointcut-ref="poi"/>
            <!-- 异常后置增强,只有当方法 执行出现异常的时候才会执行-->
            <aop:after-throwing method="ex" pointcut-ref="poi"/>
            <!-- 最终增强:无论方法是否正常执行,都会执行 -->
            <aop:after method="exit" pointcut-ref="poi"/>
        </aop:aspect>
    </aop:config>
</beans>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.ishangu</groupId>
    <artifactId>SpringAop</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.9</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.3.9</version>
        </dependency>
        <!-- 使用Aop需要的相关依赖 -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.7</version>
        </dependency>
    </dependencies>
</project>
AOP注解方法
@Aspect // 表示这个类是一个切面
@Component // 被IOC容器管理
@Order(0) // 指定AOP的执行顺序,数字越小优先级越高
public class Aop {

    @Pointcut("execution(public * com.ishangu.*.*.*(..))")
    public void method() {

    }

    /*@Before("method()")
	public void open() {
		System.out.println("开启事务");
	}

	@AfterReturning("method()")
	public void close() {
		System.out.println("关闭事务");
	}

	@AfterThrowing(pointcut = "method()", throwing = "ex")
	public void ex(Exception ex) {
		System.out.println("出现异常,回滚事务");
		ex.printStackTrace();
	}

	@After("method()")
	public void exit() {
		System.out.println("总是出现");
	}*/

    /**
	 * 环绕增强
	 */

    @Around("method()")
    public Object around(ProceedingJoinPoint join) {
        Object obj = null;
        try {
            // 前置增强 
            System.out.println("开启事务"); // 调用本身的业务层方法,并接收返回值 
            obj = join.proceed();
            System.out.println("提交事务");
        } catch (Throwable e) { //
            System.out.println("出现异常回滚事务");
            e.printStackTrace();
        } finally {
            System.out.println("关闭流");
        }
        return obj;
    }

}
<context:component-scan base-package="com.ishangu" />

<!-- 开启AOP注解 -->
<aop:aspectj-autoproxy/>

MVC

​ model、view、controller是一种专门用于web设计分层的一种设计模式

SpringMVC

​ 是Spring提供的一个MVC框架,主要目的就是解决web开发中常见的一些问题,并且可以与Spring无缝集成

SpringMVC配置
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.9</version>
</dependency>
-web.xml
<!-- 配置全局参数,告知配置文件参数 -->
<!-- <context-param>
   <param-name>contextConfigLocation</param-name>
   <param-value>classpath:application.xml</param-value>
  </context-param> -->

<!-- 配置DispatcherServlet处理所有的请求-->
<servlet>
    <servlet-name>mvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--  -->
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:application.xml</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>mvc</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>
<?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:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans  
                           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                           http://www.springframework.org/schema/context 
                           http://www.springframework.org/schema/context/spring-context-3.0.xsd
                           http://www.springframework.org/schema/mvc 
                           http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- <bean name="/he" class="com.ishangu.controller.HelloController" /> -->
    <context:component-scan base-package="com.ishangu" />
    <!-- 开启静态资源支持,因为web.xml中我们覆盖了default-servlet的路径 -->
    <mvc:default-servlet-handler />
    <!-- 开启静态资源支持,会造成找不到springmvc注解的情况,所以需要开启注解支持。 -->
    <mvc:annotation-driven conversion-service="conversionService" />
    <!-- 配置日期转换工具类 -->
    <bean id="tim" class="com.ishangu.util.TimeStampConverter" />
    <bean id="date" class="com.ishangu.util.DateConverter" />
    <!-- 将工具类配置到SpringMVC的类型转换工厂中 -->
    <bean id="conversionService"
          class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <ref bean="tim" />
                <ref bean="date" />
            </set>
        </property>
    </bean>

    <!-- 配置视图解析器 -->
    <bean
          class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="../WEB-INF/view/" />
        <property name="suffix" value=".jsp" />
    </bean>

    <!-- 配置文件上传 id必须是multipartResolver -->
    <bean id="multipartResolver"
          class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="#{1024*1024*100}"></property>
        <property name="maxInMemorySize" value="102400"></property>
        <property name="defaultEncoding" value="utf-8"></property>
    </bean>

    <!-- 配置拦截器 -->
    <bean id="t" class="com.ishangu.interceptor.TestInterceptor" />
    <mvc:interceptors>
        <mvc:interceptor>
            <!-- 拦截所有路径 -->
            <mvc:mapping path="/**" />
            <mvc:exclude-mapping path="/test/test1" />
            <ref bean="t"/>
        </mvc:interceptor>
    </mvc:interceptors>
</beans>
SpringMVC主要解决的问题
  • url的映射非常复杂,需要在web.xml中配置很多的servlet

  • 接受参数非常复杂

  • 路径跳转,以及参数传递的问题

  • 文件上传太过复杂

  • 国际化

  • 表单校验等功能

    ​ 目前我们处理前端请求的唯一方式只有servlet,所有SpringMVC对于请求的处理等操作也是基于servlet完成的,只是SpringMVC封装了一个功能特别强大的Servlet叫做DispatcherServlet,也就是说所有的请求实际上都是由DispatcherServlet进行分发处理的,所以使用SpringMVC需要配置DispatcherServlet到web.xml中

SpringMVC处理请求的两种方式
  • 实现controller接口,重写对应方法,实现处理请求
  • 通过RequestMapping注解,来映射请求路径
@RequestMapping(value = "hei1", name = "他就是一个注释",method = RequestMethod.GET,params="id")
public void method(HttpServletRequest req, HttpServletResponse resp) {
    System.out.println("hello java");
}
@RequestMapping
属性说明
value用来指定浏览器的映射路径,也就是servlet中的url-pattern
name没什么用,可以理解成@RequestMapping的注释
method用来指定当前方法,处理那种类型的请求,如果没有指定该属性,证明这个方法可以处理任意请求
params用来指定访问当前路径时,必须携带什么参数,如果没有携带则无法访问(400)
headers用来指定访问当前路径,必须包含哪些请求头,如果没有则禁止访问
consumes用来指定请求的数据类型必须是哪种,例如指定text/html
produces用来指定响应的数据类型必须是哪种,指定的类型必须包含在请求头中
SpringMVC接收参数的方式
  • 使用servlet原生api接收
@RequestMapping("params1")
public void param1(HttpServletRequest req, HttpServletResponse resp) throws ParseException {
    String name = req.getParameter("name");
    String password = req.getParameter("password");
    String age = req.getParameter("age");
    String createTime = req.getParameter("createTime");
    SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd");
    Date date = sd.parse(createTime);
    User user = new User(name, password, Integer.valueOf(age), date, null, null);
    System.out.println(user);
}
  • 通过形参列表接收参数
@RequestMapping("params2")
public void param2(String name, String password, Integer age, Date createTime, java.sql.Date createTime2,Timestamp createTime3, HttpServletRequest req, HttpServletResponse resp) throws ParseException {
    User user = new User(name, password, Integer.valueOf(age), createTime, createTime2, createTime3);
    System.out.println(user);
}
  • 通过形参model接收形参
@RequestMapping("params3")
public void param3(User user, HttpServletRequest req, HttpServletResponse resp) {
    System.out.println(user);
}
  • 在RequestMapping的value中指定一个变量,然后在形参中通过注解接收参数
@RequestMapping("params4/{id}/{admin}")
public void param4(@PathVariable("id") int id, @PathVariable("admin") String admin, HttpServletRequest req, HttpServletResponse resp) {
    System.out.println(id + "111" + admin);
}
SpringMVC手动获取不能接收的参数类型
/**
 * 让SpringMVC形参支持Timestamp类型
 * Converter的两个泛型:分别是数据请求中原本类型,以及需要转成的类型
 */
public class TimeStampConverter implements Converter<String, Timestamp>{

    @Override
    public Timestamp convert(String arg0) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Date date = null;
        try {
            date = format.parse(arg0);
        } catch (Exception e) {
            // TODO: handle exception
        }
        return new Timestamp(date.getTime());
    }

}
<!-- 开启静态资源支持,因为web.xml中我们覆盖了default-servlet的路径 -->
<mvc:default-servlet-handler/>
<!-- 开启静态资源支持,会造成找不到springmvc注解的情况,所以需要开启注解支持。 -->
<mvc:annotation-driven conversion-service="conversionService"/>
    <!-- 配置日期转换工具类 -->
<bean id="tim" class="com.ishangu.util.TimeStampConverter"/>
<bean id="date" class="com.ishangu.util.DateConverter"/>	
<!-- 将工具类配置到SpringMVC的类型转换工厂中 -->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <property name="converters">
        <set>
            <ref bean="tim"/>
            <ref bean="date"/>
        </set>
    </property>
</bean>
JSON

​ 只是一个单纯的字符串而已,不过这个字符串符合了特定的格式,经常用于和前端js交互数据使用

  • 格式

    key : value

  • key

    需要在双引号之内

  • value

    字符串类型的value需要在双引号之内,数值类型则不需要

  • {}

    一个{}代表一个json对象,一个json对象中可以有数量不定的key:value,使用逗号分隔

  • []

    一个[]代表一个json数组,一个json中可以有任意个json对象,使用逗号分割

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.13.0</version>
</dependency>
/**
 * @ResponseBody 如果返回的是非字符串与包装类,则会将返回值直接转成json格式 ,返回给调用者
 *
 */
@ResponseBody
@RequestMapping("test3")
public User test3(HttpServletRequest req, HttpServletResponse resp) {
    return new User("123", "1123", 12, null, null, null);
}
路径跳转以及参数传递
@RequestMapping("test1")
public void test1(HttpServletRequest req, HttpServletResponse resp) throws Exception {
    req.setAttribute("msg", "今天天气好冷");
    req.getRequestDispatcher("show.jsp").forward(req, resp);
}

@RequestMapping("test2")
public ModelAndView test2(HttpServletRequest req, HttpServletResponse resp) throws Exception {
    ModelAndView mv = new ModelAndView();
    // 添加的数据没有key值,取值的时候使用类型名称(首字母小写)取值
    mv.addObject(new User("123", "1123", 12, null, null, null));
    mv.addObject("昨天元宵节");
    // 通过key value传递数据
    mv.addObject("msg", "前天情人节");
    Map<String, Integer> map = new HashMap<>();
    map.put("key1", 1111);
    map.put("key2", 2222);
    map.put("key3", 3333);
    // 直接传递一个map数据
    mv.addAllObjects(map);
    mv.setViewName("show.jsp");
    return mv;
}

/**
 * @ResponseBody 如果返回的是非字符串与包装类,则会将返回值直接转成json格式 ,返回给调用者
 *
 */
@ResponseBody
@RequestMapping("test3")
public User test3(HttpServletRequest req, HttpServletResponse resp) {
    return new User("123", "1123", 12, null, null, null);
}

/**
 * 返回值是字符串,直接通过return字符串来表示跳转路径
 */
@RequestMapping("test4")
public String test4(HttpServletRequest req, HttpServletResponse resp) {
    return "add.jsp";
}
视图解析器
<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="../WEB-INF/view/"/>
    <property name="suffix" value=".jsp"/>
</bean>
SpringMVC使用重定向
/**
 * 1:当使用SpringMVC想重定向的时候怎么处理
 * redirect:重定向
 * forward:请求转发
 * 使用redirect:forward:可以跳过视图解析器,直接走指定的视图,并且使用他们可以跳转到其他的RequestMapping路径
 */
@RequestMapping("test5")
public String test5(HttpServletRequest req, HttpServletResponse resp) {
    //return "redirect:index.html";
    return "forward:index.html";
}
SpringMVC文件上传
  • xml中需要提供文件上传组件的配置
<!-- 配置文件上传 id必须是multipartResolver-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize" value="#{1024*1024*100}"></property>
    <property name="maxInMemorySize" value="102400"></property>
    <property name="defaultEncoding" value="utf-8"></property>
</bean>
@RequestMapping("upload")
public void upload(MultipartFile file, HttpServletRequest req, HttpServletResponse resp) throws Exception {
    file.transferTo(new File("D://文件//" + file.getOriginalFilename()));
}
  • spring在文件上传的时候需要使用commons-fileupload 的依赖
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.4</version>
</dependency>
SpringMVC文件下载
@RequestMapping("download")
public void download(String name, HttpServletResponse resp) throws Exception {
    resp.setHeader("Content-Disposition", "attachment; filename=" + name);
    InputStream in = new FileInputStream(new File("D:\\ssm\\SpringMVC_1\\src\\main\\webapp\\1001.jpg"));
    IOUtils.copy(in, resp.getOutputStream());
    in.close();
}
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.11.0</version>
</dependency>
拦截器

​ SpringMVC提供的一个组件,可以拦截所有的请求以及静态资源,但是不拦截jsp,使用拦截器需要将其配置在SpringMVC的配置文件中

<!-- 配置拦截器 -->
<bean id="t" class="com.ishangu.interceptor.TestInterceptor" />
<mvc:interceptors>
    <mvc:interceptor>
        <!-- 拦截所有路径 -->
        <mvc:mapping path="/**" />
        <mvc:exclude-mapping path="/test/test1" />
        <ref bean="t"/>
    </mvc:interceptor>
</mvc:interceptors>
public class TestInterceptor implements HandlerInterceptor {
    /**
	 * 确定访问的映射存在的情况下,在调用handler之前执行,返回true表示放行,返回false表示不放行
	 *
	 */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
        throws Exception {
        System.out.println("在调用handler之前执行,返回true表示放行,返回false表示不放行");
        return true;
    }

    /**
	 * 在handler执行完之后,跳转视图之前执行
	 */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {
        System.out.println("跳转视图之前执行");
    }

    /**
	 * 返回视图之后执行
	 */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
        throws Exception {
        System.out.println("返回视图之后执行");
    }
}
SpringMVC请求流程
  • 用户发送请求到Tomcat
  • Tomcat将符合DispatcherServlet路径的请求交给DispatcherServlet(前端控制器)进行处理
  • DispatcherServlet去请求HandleMapping查找Handle(根据XML配置以及注解配置查找)
  • HandleMapping(处理器请求器)会将请求映射成HandleExecutionChain处理器执行链对象,里面包含(handler,interceptorList),然后将其返回给前端控制器
  • DispatcherServlet调用合适的HandlerAdapter(处理器适配器)来执行Handle
  • Handle执行完成之后,会返回一个ModelAndView对象给HandlerAdapter
  • HandlerAdapter将ModelAndView对象返回给DispatcherServlet
  • DispatcherServlet请求ViewReslover(视图解析器)来解析视图(将逻辑视图转成物理视图)
  • 视图解析器返回View给DispatcherServlet
  • DispatcherServlet对视图进行渲染(将返回给前端的数据,填充到页面的request作用域之中)
  • DispatcherServlet响应用户
SpringMVC全局异常处理
/**
 * 在一个比较严谨的项目中,所有的异常需要记录日志,然后后期维护人员根据日志的记录来进行维护
 * 由于我们目前没有学习日志框架,所以我们只能使用最基本的IO流来代替日志框架
 * @throws IOException 
 */
@ExceptionHandler(NullPointerException.class)
public String nullException(HttpServletRequest req,NullPointerException ex) throws IOException{
    // 模拟日志记录
    OutputStream out = new FileOutputStream(new File("D:\\err.log"),true);
    StringBuffer sb = new StringBuffer();
    sb.append("时间:");
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    sb.append(format.format(new Date()));
    sb.append("   请求:"+req.getRequestURI()+"出现空指针异常!\n");
    out.write(sb.toString().getBytes());
    out.flush();
    ex.printStackTrace(new PrintWriter(out,true));
    out.close();
    return "error";
}
增强Controller
@ControllerAdvice的功能
  • 全局异常处理

  • 全局参数预处理(当多个model类的属性名重复,并且在一个页面中添加)

@InitBinder("a")// 指定预处理参数名称,需要在COntroller形参中配置@ModelAttribute("a")使用
public void user(WebDataBinder binder){
    // 用于前端页面,在相同的参数名称name值前加上a.前缀
    binder.setFieldDefaultPrefix("a.");
}
@InitBinder("b")
public void user2(WebDataBinder binder){
    binder.setFieldDefaultPrefix("b.");
}
@RequestMapping("addUser")
public String addUser(@ModelAttribute("a")User user,@ModelAttribute("b")User2 user2) {
    // 添加用户
    System.out.println(user);
    System.out.println(user2);
    userSer.save(user);
    return "forward:listAllUser";
}
  • 给所有的Controller绑定一些参数,类似于web.xml中的<context-param>
@ModelAttribute("mapp")
public Map<String, String> mapp(){
    Map<String, String> map = new HashMap<>();
    map.put("name", "admin");
    map.put("ps", "123");
    return map;
}

@ModelAttribute("app")
public String app(){
    String string = "123";
    return string;
}
/**
 * 取出Controller绑定的参数
 * @param model
 * @return
 */
@RequestMapping("method")
public String method(Model model) {
    Map<String, Object> map = model.asMap();
    Collection<Object> values = map.values();
    Iterator<Object> it = values.iterator();
    while (it.hasNext()) {
        System.out.println(it.next());
    }
    /*System.out.println(map.get("mapp"));
		System.out.println(map.get("app"));*/
    return "userPage/userAdd";
}
SpringMVC出现404的解决思路
  • 确定404页面的Message信息是否有对应的RequestMapping
  • 如果RequestMapping注解存在则确定是否写Controller注解
  • 如果RequestMapping注解存在,则检查配置文件<context:component-scan base-package="com.ishangu"/>是否出现错误以及开启注解驱动<mvc:annotation-driven/>
  • 如果上面都没问题,则检查.class文件查看最后编译日期,确定是否是编译型问题

MyBatis

​ MyBatis是一个优秀的持久层框架,它支持定制化SQL,存储过程以及存储函数等内容,Mybatis几乎避免了所有的JDBC代码以及手动设置参数,结果集的解析等

​ MyBatis可以使用简单的xml或注解来配置映射的原生信息,将接口和Java的POJO(就是我们的model类,普通Java对象)映射成数据库的记录,以及针对数据库进行CRUD等操作

​ 每个MyBatis应用程序主要都是使用SqlSessionFactory实例的,一个SqlSessionFactory实例可以通过SqlSessionFactoryBuilder获得。SqlSessionFactoryBuilder可以从一个xml配置文件或者一个预定义的配置类的实例获得

​ 用xml文件构建SqlSessionFactory实例是非常简单的事情。推荐在这个配置中使用类路径资源(classpath resource),但你可以使用任何Reader实例,包括用文件路径或file://开头的url创建的实例。MyBatis有一个实用类----Resources,它有很多方法,可以方便地从类路径及其它位置加载资源

  • 有一个xml总配置文件
  • 使用Resource读取配置文件获得字节流
  • 使用SqlSessionFactoryBuilder根据字节流创建SqlSessionFactory实例
  • 通过SqlSession调用sql语句
MyBatis的配置文件
  • config配置文件,用来配置数据库环境,事务管理,别名,MyBatis插件,加载小配置文件等
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="a">
        <!-- 配置数据库环境 -->
        <environment id="a">
            <!-- 使用MyBatis自带的事务管理器 -->
            <transactionManager type="org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory"/>
            <!-- 使用MyBatis自带的数据源 -->
            <dataSource type="org.apache.ibatis.datasource.pooled.PooledDataSourceFactory">
                <property name="driver" value="com.mysql.jdbc.Driver"/>

                <property name="url" value="jdbc:mysql:///t"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
	<!-- 加载小配置文件 -->
    <mappers>
        <mapper resource="mapper/usermapper.xml"/>
    </mappers>
</configuration>
  • mapper配置文件,每个mapper配置文件都对应一个dao层接口,在mapper配置文件中实现接口的CRUD操作
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 由于namespace中填写了接口的全限定名,所以这个xml与UserDao接口进行了绑定 -->
<mapper namespace="com.ishangu.dao.UserDao">
	<insert id="save" parameterType="com.ishangu.model.User">
		insert into user values(#{uid},#{uname},#{upassword},#{urealname},#{uaddTime},#{ustatus});
	</insert>
	
	<delete id="delete" parameterType="int">
		delete from user where uid=#{id};
	</delete>
	
	<update id="update" parameterType="com.ishangu.model.User">
		update user set uname=#{uname},upassword=#{upassword},urealname=#{urealname},uadd_time=#{uaddTime},ustatus=#{ustatus} where uid=#{uid};
	</update>
	
	<select id="byId" parameterType="int" resultType="com.ishangu.model.User">
		select * from user where uid=#{id};
	</select>
	
	<select id="findAll" resultType="com.ishangu.model.User">
		select * from user;
	</select>
	
	<!-- <resultMap type="com.ishangu.model.User" id="uMap">
		<id column="uid" property="uid"/>
	</resultMap> -->
	
	<select id="login" resultType="com.ishangu.model.User">
		select * from user where uname=#{name} and upassword=#{password};
	</select>
</mapper>
MyBatis默认支持几个参数

​ Mybatis中默认只支持传递一个参数,无论这个参数是什么类型的,所以parameterType可以省略不写

如何解决MyBatis传参多个的问题
  • 由于MyBatis只能传递一个参数,所以我们可以将多个参数封装称map,然后传递过来,在sql语句中使用map的key值来获取value
<select id="login" resultType="com.ishangu.model.User">
    select * from user where uname=#{name} and upassword=#{password};
</select>
Map< String, String> map = new HashMap<String, String>();
map.put("name", "zx");
map.put("password", "123456");
System.out.println(dao.login(map));
User login(Map<String, String> map);
  • 自己手写map太过麻烦,所以可以使用MyBatis提供的@Param(“key”)注解来让其在解析的时候自动生成map对象
<select id="login" resultType="com.ishangu.model.User">
    select * from user where uname=#{name} and upassword=#{password};
</select>
User login(@Param("name")String name,@Param("password")String password);
  • MyBatis会将参数封装到一个集合中,可以使用#{arg下标}取值
<select id="login" resultType="com.ishangu.model.User">
    select * from user where uname=#{arg0} and upassword=#{arg1};
</select>
User login(String name,String password);
#与$的区别
  • 在MyBatis中#和$都能从对象中取值,两者的区别在于
    • #使用的是预编译对象(常用的)
    • $使用的是Statement非预编译对象(不常用)
MyBatis中转义字符

​ 在xml中>和<会造成标签解析错误,所以有了一些转义字符

转义字符含义
&lt;<小于
&gt;>大于
&amp;&
&apos;单引号
&quot;"双引号
动态sql
  • set
    • 可以自动添加关键字
    • 如果作用域之内最后一位是逗号的话,可以自动去掉逗号
  • if
    • 如果test中的值为true则拼接if之内的sql语句,如果为false则不拼接
<update id="update">
    update user 
    <set>
        <if test="uname!=null">
            uname=#{uname},
        </if>
        <if test="upassword!=null">
            upassword=#{upassword},
        </if>
        <if test="urealname!=null">
            urealname=#{urealname},
        </if>
        <if test="uaddTime!=null">
            uadd_time=#{uaddTime},
        </if>
        <if test="ustatus!=null">
            ustatus=#{ustatus}
        </if>		
    </set>
    where uid=#{uid};
</update>
  • where
    • 可以自动添加where关键字
    • 如果where后面直接跟着的是and 或者 or的话,会去掉and 或or
  • choose
    • 类似于Java中的switch
    • when
      • choose的内置标签,相当于Java中的case,多个when永远只会匹配一个
    • otherwoise
      • 当所有的when标签都没有匹配成功的时候则会拼接otherwise的sql
  • bind
    • 功能是字符串拼接
    • 会将value中拼接的字符串赋值给name里面声明的变量在sql中使用#{name值}可以取出
<select id="findLike" resultMap="aaa" resultType="com.ishangu.model.User">
    select * from user
    <where>
        <choose>
            <when test="uname!=null">
                uname like concat('%',#{uname},'%')
            </when>
            <when test="upassword!=null">
                <bind name="upassword" value="'%'+upassword+'%'"/>
                upassword like #{upassword}
            </when>
            <when test="urealname!=null">
                <bind name="urealname" value="'%'+urealname+'%'"/>
                urealname like #{urealname}
            </when>
            <when test="ustatus!=null">
                <bind name="ustatus" value="'%'+ustatus+'%'"/>
                ustatus like #{ustatus}
            </when>
            <otherwise>
                uid = 4
            </otherwise>
        </choose>
    </where>
</select>
  • trim
    • 可以自动添加指定的前缀或者后缀
    • 可以自动去掉指定的前缀或后缀,多个值之间使用|分割
<select id="findAll" resultMap="aaa" resultType="com.ishangu.model.User">
    select * from user
    <trim prefix="where" prefixOverrides="addd|aaa|abc|and">
        <include refid="a"></include>
    </trim>
</select>
  • foreach
    • collection
      • 里面填写参数的key,或者填写集合的类型,建议配合@Param注解填写参数的key
    • item
      • 每次从集合中取值赋给item中声明的变量
    • index
      • 遍历时候集合的下标索引
    • separator
      • 遍历时候需要插入的分隔符
    • open
      • 循环开始之前需要先插入的数据
    • close
      • 循环结束之后需要补充的数据
<delete id="deleteAll">
    delete from user where uid in(
    <foreach collection="array" item="i" separator=",">
        #{i}
    </foreach>
    )
</delete>
  • sql
    • 可以将共用的代码抽离出来形成一个单独的个体
<sql id="a">
    <if test="uname!=null">
        and uname=#{uname}
    </if>
    <if test="upassword!=null">
        and upassword=#{upassword}
    </if>
    <if test="urealname!=null">
        and urealname=#{urealname}
    </if>
    <if test="uaddTime!=null">
        and uadd_time=#{uaddTime}
    </if>
    <if test="ustatus!=null">
        and ustatus=#{ustatus}
    </if>
    <if test="uid!=null">
        and uid=#{uid}
    </if>
</sql>
  • include
    • 可以引用sql标签抽离的代码
<select id="findAll" resultMap="aaa" resultType="com.ishangu.model.User">
    select * from user
    <trim prefix="where" prefixOverrides="addd|aaa|abc|and">
        <include refid="a"></include>
    </trim>
</select>
  • selectKey
    • 查询获取主键的值
<insert id="save" keyColumn="uid" keyProperty="uid" useGeneratedKeys="true">
    <!--<selectKey keyColumn="uid" keyProperty="uid" order="AFTER" resultType="int">
      select last_insert_id()
   </selectKey>-->
    insert into user values(#{uid},#{uname},#{upassword},#{urealname},#{uaddTime},#{ustatus});
</insert>
数据库中表的关系
  • 一对多
<!-- 查询n+1条sql语句 -->
<resultMap id="dMap" type="com.ishangu.model.Dept">
    <id column="deptno" property="deptno"/>
    <result column="dname" property="dname"/>
    <collection property="emps" select="com.ishangu.dao.EmpDao.findByDeptno" column="deptno" ofType="com.ishangu.model.Emp">
        <id column="empno" property="empno"/>
        <result column="ename" property="ename"/>
        <result column="job" property="job"/>
        <result column="mgr" property="mgr"/>
        <result column="hiredate" property="hiredate"/>
        <result column="sal" property="sal"/>
        <result column="comm" property="comm"/>
        <result column="deptno" property="deptno"/>
    </collection>
</resultMap>
<!-- 普通的一对多 -->
<resultMap id="dMap" type="com.ishangu.model.Dept">
    <id column="deptno" property="deptno"/>
    <result column="dname" property="dname"/>
    <collection property="emps" ofType="com.ishangu.model.Emp">
        <id column="empno" property="empno"/>
        <result column="ename" property="ename"/>
        <result column="job" property="job"/>
        <result column="mgr" property="mgr"/>
        <result column="hiredate" property="hiredate"/>
        <result column="sal" property="sal"/>
        <result column="comm" property="comm"/>
        <result column="deptno" property="deptno"/>
    </collection>
</resultMap>
public class Dept {
    private Integer deptno;
    private String dname;
    private String loc;
    // 一个部门下有多个员工
    private List<Emp> emps;
}
  • 多对一
<resultMap id="eMap" type="com.ishangu.model.Emp">
    <id column="empno" property="empno"/>
    <result column="ename" property="ename"/>
    <result column="job" property="job"/>
    <result column="mgr" property="mgr"/>
    <result column="hiredate" property="hiredate"/>
    <result column="sal" property="sal"/>
    <result column="comm" property="comm"/>
    <result column="deptno" property="deptno"/>
    <association property="dept" javaType="com.ishangu.model.Dept">
        <id column="deptno" property="deptno"/>
        <result column="dname" property="dname"/>
    </association>
</resultMap>
public class Emp {
    private Integer empno;
    private String ename;
    private String job;
    private Integer mgr;
    private Date hiredate;
    private BigDecimal sal;
    private BigDecimal comm;
    private Integer deptno;
    // 代表每个员工
    private Dept dept;
}
  • 多对多
MyBatis中的一级缓存和二级缓存
  • 一级缓存

    • sqlsession的级别,当SSM整合的时候sqlsession是由Spring容器去管理的,所以在SSM的时候一级缓存是无效的
  • 二级缓存

    • SqlSessionFactory级别,也叫mapper级别,缓存的数据可以在多个SqlSession之间进行共享,由于二级缓存是mapper级别的,所以使用二级缓存的时候我们需要在mapper配置文件中开启缓存,并且在config配置文件中也开启二级缓存
  • 使用MyBatis二级缓存的时候,model类必须要实现Serializable(序列化)接口

MyBatis在什么时候添加的二级缓存
  • MyBatis是在SqlSession关闭的时候,将一级缓存的数据存储到二级缓存之中
  • MyBatis中执行查询的都是SqlSession,当我们使用二级缓存的时候一级缓存也是同样存在的,在SqlSession执行查询之后,会将查询的结果缓存到一级缓存之中,然后在SqlSession关闭的时候将数据添加到二级缓存之中(MyBatis中的缓存我们可以理解成一个Map容器,namespace+id就是map的key,查询出来的数据就是map的value,MyBatis每次查询的时候都会先从缓存中查询二级缓存中是否包含,如果没有则从一级缓存中查询,如果一级缓存中还是没有的话则从数据库中查询,然后将数据添加到一级缓存之内)
MyBatis的二级缓存分为两种
  • MyBatis自带的二级缓存
  • 使用第三方数据库(Redis数据库)进行缓存4
<settings>
    <!-- 开启二级缓存 -->
    <setting name="cacheEnabled" value="true"/>
</settings>
开启缓存
  • eviction

    指缓存回收策略

  • LRU

    回收最近最少使用的缓存

  • FIFO

    先入先出策略,按照添加顺序回收内存

  • SOFT

    软引用

  • WEAK

    弱引用

  • flushInterval

    指缓存刷新的时间间隔(毫秒)

  • size

    指缓存能存储多少个对象,值如果过大会导致内存溢出

  • readOnly

    指缓存是只读的

<cache eviction="LRU" size="1024" flushInterval="111" readOnly="true"/>
@Test
public void save() throws IOException {
    Reader reader = Resources.getResourceAsReader("MyBatisConfig.xml");
    SqlSessionFactoryBuilder sqlBuilder = new SqlSessionFactoryBuilder();
    SqlSessionFactory factory = sqlBuilder.build(reader);
    SqlSession session = factory.openSession();
    //DeptDao dao = session.getMapper(DeptDao.class);
    /*Dept byDeptno = dao.findByDeptno(20);
    System.out.println(byDeptno);*/
    /*List<Dept> all = dao.findAll();
    System.out.println(all);*/
    EmpDao dao = session.getMapper(EmpDao.class);
    System.out.println(dao.findByEmpno(7499));
    session.commit();
    session.close();
    SqlSession session2 = factory.openSession();
    EmpDao dao2 = session2.getMapper(EmpDao.class);
    System.out.println(dao2.findByEmpno(7499));
    session2.commit();
    session2.close();
    reader.close();
}

SSM整合

准备依赖

  • 准备依赖(jar包)
  • SpringMVC
  • 数据库驱动
  • SpringJDBC(管理事务)
  • Aop
  • MyBatis
  • MyBatis-Spring
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.ishangu</groupId>
    <artifactId>SSM</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <dependencies>
        <!-- Spring与SpringMVC相关 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>

        <!-- Spring-jdbc相关依赖 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.13.0</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.7</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version>
        </dependency>

        <!-- MySQL驱动包 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

        <!-- MyBatis整合Spring的依赖 -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.6</version>
        </dependency>

        <!-- 阿里的德鲁伊数据库连接池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.6</version>
        </dependency>

        <!--jstl-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
    </dependencies>
</project>

准备配置文件

  • Spring的配置文件
  • MyBatisConfig配置文件
  • mapper配置文件
  • db.properties数据库相关配置文件
<?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:mvc="http://www.springframework.org/schema/mvc"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans  
                           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                           http://www.springframework.org/schema/context 
                           http://www.springframework.org/schema/context/spring-context-3.0.xsd
                           http://www.springframework.org/schema/mvc 
                           http://www.springframework.org/schema/mvc/spring-mvc.xsd
                           http://www.springframework.org/schema/util 
                           http://www.springframework.org/schema/util/spring-util.xsd">
    <context:component-scan base-package="com.ishangu"/>
    <mvc:annotation-driven conversion-service="conversionServiceFactory"/>
    <mvc:default-servlet-handler/>
    <util:properties id="d" location="classpath:db.properties"/>
    <!-- 配置数据库连接池 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="username" value="#{d.username}"/>
        <property name="password" value="#{d.password}"/>
        <property name="url" value="#{d.url}"/>
        <property name="driverClassName" value="#{d.driver}"/>
        <property name="initialSize" value="#{d.initalSize}"/>
    </bean>
    <!--3: 配置MyBatis的sql会话工厂sqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="configLocation" value="classpath:MyBatisConfig.xml"/>
        <property name="mapperLocations" value="classpath:mapper/*.xml"/>
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- 4:配置Dao层接口所在的位置,Spring就能调用sqlSessionFactory给接口创建代理类 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.ishangu.dao"/>
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>

    <!-- 配置日期转换工具类 -->
    <bean id="timeStamp" class="com.ishangu.util.TimeStampConverter"/>
    <!-- 将工具类配置到SpringMVC的类型转换工厂中 -->
    <bean id="conversionServiceFactory" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <ref bean="timeStamp"/>
            </set>
        </property>
    </bean>

    <!--视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <!-- 拦截器 -->
    <bean id="interceptor" class="com.ishangu.interceptor.EncodingInterceptor"/>
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <mvc:exclude-mapping path="index.html"/>
            <ref bean="interceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>
</beans>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值