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中>和<会造成标签解析错误,所以有了一些转义字符
转义 | 字符 | 含义 |
---|---|---|
< | < | 小于 |
> | > | 大于 |
& | & | 与 |
' | ’ | 单引号 |
" | " | 双引号 |
动态sql
- set
- 可以自动添加关键字
- 如果作用域之内
最后一位
是逗号的话,可以自动去掉逗号
- if
- 如果test中的值为
true
则拼接if之内的sql语句,如果为false
则不拼接
- 如果test中的值为
<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
- 循环结束之后需要补充的数据
- collection
<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配置文件中也开启二级缓存
- SqlSessionFactory级别,也叫
-
使用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>