框架知识点总结
Mybatis
1. 框架概述
1 | 框架(Framework)是某种应用的半成品,是一组组件,供你选用完成你自己的系统。通过框架,可以将应用自身的设计和具体的实现技术解耦,这样,软件的研发将集中在应用的设计上,而不是具体的技术实现。框架一般处在低层应用平台(如J2EE)和高层业务逻辑之间的中间层。 |
1 | MyBatis 是一款优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和POJOs映射成数据库中的记录,使开发者只需要关注sql语句本身,而不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。 |
2. Mybatis快速入门
- 在pom.xml文件中添加Mybatis3.4.5,mysql,log4j的坐标
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 > <dependencies>
> <dependency>
> <groupId>org.mybatis</groupId>
> <artifactId>mybatis</artifactId>
> <version>3.4.5</version>
> </dependency>
> <dependency>
> <groupId>mysql</groupId>
> <artifactId>mysql-connector-java</artifactId>
> <version>5.1.6</version>
> <scope>runtime</scope>
> </dependency>
> <dependency>
> <groupId>log4j</groupId>
> <artifactId>log4j</artifactId>
> <version>1.2.12</version>
> </dependency>
> </dependencies>
>
编写持久层接口的映射文件XXXDao.xml
- 创建位置:创建在resources文件中,但必须和持久层接口在相同的包中
- 名称:必须以持久层接口名称命名文件名,扩展名是.xml
1
2
3
4
5
6
7
8
9
10
11 >
>
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
> "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
> <mapper namespace="dao.IUserDao">
> <!--配置查询所有-->
> <select id="findAll" resultType="domain.User">
> select * from user
> </select>
> </mapper>
>
编写SqlMapConfig.xml配置文件
- 创建位置:创建在resources文件中
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 >
>
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
> "http://mybatis.org/dtd/mybatis-3-config.dtd">
> <!-- mybatis的主配置文件 -->
> <configuration>
> <!-- 引入properties文件 -->
> <properties resource="jdbcConfig.properties"></properties>
> <!-- 批量别名定义,扫描整个包下的类,别名为类名 -->
> <typeAliases>
> <package name="domain"></package>
> </typeAliases>
> <!-- 配置环境 -->
> <environments default="mysql">
> <!-- 配置mysql的环境-->
> <environment id="mysql">
> <!-- 配置事务的类型-->
> <transactionManager type="JDBC"></transactionManager>
> <!-- 配置数据源(连接池) -->
> <dataSource type="POOLED">
> <!-- 配置连接数据库的4个基本信息 -->
> <property name="driver" value="${jdbc.driver}"></property>
> <property name="url" value="${jdbc.url}"></property>
> <property name="username" value="${jdbc.username}"></property>
> <property name="password" value="${jdbc.password}"/>
> </dataSource>
> </environment>
> </environments>
>
> <!-- 注册指定包下的所有mapper接口(xml文件) -->
> <mappers>
> <package name="dao"></package>
> </mappers>
> </configuration>
>
- 编写测试类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 > public static void main(String[] args) throws IOException {
> //1.读取主配置文件,通过类加载器获得输入流对象
> InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
> //2.创建SqlSessionFactory的构建者对象
> SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
> //3.使用构建者创建工厂对象SqlSessionFactory
> SqlSessionFactory factory = builder.build(in);
> //4.创建SqlSession对象,SqlSession对象就可以对数据库进行增删改查
> SqlSession session = factory.openSession();
> //5.根据SqlSession对象获取dao接口的代理对象
> IUserDao userDao = session.getMapper(IUserDao.class);
> //6.执行代理对象中的具体方法
> List<User> users = userDao.findAll();
> for (User user : users) {
> System.out.println(user);
> }
> //7.释放资源
> session.close();
> in.close();
> }
>
基于注解的mybatis使用
在持久层接口中添加注解,不再需要持久层接口的映射文件
1
2
3
4
5 > public interface IUserDao {
> "select * from user") (
> List<User> findAll();
> }
>
修改SqlMapConfig.xml
1
2
3
4
5
6
7
8 > <mappers>
> <!--使用注解方式配置映射信息-->
> <mapper class="dao.IUserDao"/>
> <!--使用映射配置文件路径-->
> <!-- <mapper resource="dao/IUserDao.xml"/> -->
> <!--如果配置文件和注解方式同时存在,则会报错-->
> </mappers>
>
在使用基于注解的Mybatis配置时,请移除xml的映射配置(IUserDao.xml)
3. 基于代理Dao实现CRUD操作
1 |
|
1 | //测试类 |
#{}与${}的区别:
#{}
表示一个占位符号,通过实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换,可以有效防止sql注入。 接收简单类型值或pojo属性值。${}
表示拼接sql串,通过将parameterType传入的内容拼接在sql中且不进行jdbc类型转换,可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。
4. SqlMapConfig.xml配置文件
SqlMapConfig.xml中配置的内容和顺序
1 | -properties(属性) |
自定义别名
1
2
3
4
5
6
7 > <typeAliases>
> <!-- 单个别名定义 -->
> <typeAlias alias="user" type="com.itheima.domain.User"/>
> <!-- 批量别名定义,扫描整个包下的类,别名为类名(首字母大写或小写都可以) -->
> <package name="com.itheima.domain"/> <package name="其它包"/>
> </typeAliases>
>
mappers(映射器)
- 使用相对于类路径的资源:
<mapper resource="com/itheima/dao/IUserDao.xml"/>
- 使用mapper接口类路径:
<mapper class="com.itheima.dao.UserDao"/>
- 注册指定包下的所有mapper接口:
<package name="cn.itcast.mybatis.mapper"/>
5. Mybatis连接池
Mybatis将它自己的数据源dataSource分为三类:
- POOLED:使用连接池的数据源,MyBatis会创建PooledDataSource实例
- UNPOOLED:不使用连接池的数据源,MyBatis会创建UnpooledDataSource实例
- JNDI:使用JNDI实现的数据源,MyBatis会从JNDI服务上查找DataSource实例,然后返回使用
1 | <!-- 配置数据源(连接池)信息 --> |
当我们需要创建SqlSession对象并需要执行SQL语句时,MyBatis才会去调用dataSource对象来创建java.sql.Connection对象。也就是说,java.sql.Connection对象的创建一直延迟到执行SQL语句的时候。
6. Mybatis事务控制
1 | Mybatis框架是对JDBC的封装,所以Mybatis框架的事务控制方式是用JDBC的setAutoCommit()方法来设置事务提交方式的。在连接池中取出的连接,都会调用connection.setAutoCommit(false)方法实现事务提交。通过设定 |
7. 动态sql语句
1 | <!-- 抽取重复的语句代码片段 --> |
标签说明:
<Sql>
:将重复的sql提取出来,使用时用<include>
引用即可,最终达到sql重用的目的。<where>
:用于条件拼装<if>
:标签中test属性中写的是对象的属性名,不为空时加入sql条件语句<foreach>
:用于遍历集合,它的属性:
- collection:代表要遍历的集合元素,注意编写时不要写#{}
- open:代表语句的开始部分
- close:代表结束部分
- item:代表遍历集合的每个元素,生成的变量名
- sperator:代表分隔符
8. 一对一查询
以Account表(账户表)关联User表(用户表)为例:
在Account类中加入User类的对象作为Account类的一个属性,并添加GetterSetter方法
在AccountDao.xml中定义封装Account和User的resultMap
1
2
3
4
5
6
7
8
9
10
11
12
13
14 > <resultMap id="accountUserMap" type="account">
> <id property="id" column="aid"/>
> <result property="uid" column="uid"/>
> <result property="money" column="money"/>
> <!-- 一对一的关系映射:配置封装user的内容-->
> <association property="id" column="uid" javaType="user">
> <id property="id" column="id"/>
> <result column="username" property="username"/>
> <result column="address" property="address"/>
> <result column="sex" property="sex"/>
> <result column="birthday" property="birthday"/>
> </association>
> </resultMap>
>
配置sql语句
1
2
3
4 > <select id="findAll" resultMap="accountUserMap">
> select u.*,a.id as aid,a.uid,a.money from account a , user u where u.id = a.uid;
> </select>
>
association标签
- property:映射到列结果的字段或属性。
- column:用来传给另一个表的值所在列,一般为两个表关联的主键。
- javaType:一个 Java 类的完全限定名,或一个类型别名,表示封装的类型。
- select:另外一个查询语句的id,column属性中指定的列的值将被传递给目标select语句作为参数。
9. 一对多查询
以User表(用户表)关联Account表(账户表)为例:
在User类中加入Account类的对象作为User类的一个属性,并添加GetterSetter方法
在UserDao.xml中定义封装User和Account的resultMap
1
2
3
4
5
6
7
8
9
10
11
12
13
14 > <resultMap id="userMap" type="user">
> <id property="id" column="id"/>
> <result property="username" column="username"/>
> <result property="address" column="address"/>
> <result property="sex" column="sex"/>
> <result property="birthday" column="birthday"/>
> <!-- 配置user对象中accounts集合的映射 -->
> <collection property="accounts" ofType="account">
> <id column="aid" property="id"/>
> <result column="uid" property="uid"/>
> <result column="money" property="money"/>
> </collection>
> </resultMap>
>
配置sql语句
1
2
3
4 > <select id="findAll" resultMap="userMap">
> select u.*,a.id as aid ,a.uid,a.money from user u left outer join account a on u.id =a.uid
> </select>
>
collection标签
- property:关联查询的结果集存储在User对象的哪个属性里
- ofType:指定关联查询的结果集中的对象类型,即List对象中的泛型。可使用别名,也可使用全限定名。
10. 延迟加载
1 | 延迟加载:在需要用到数据时才进行加载,不需要用到数据时就不加载数据,也称懒加载。 |
通过assocation实现延迟加载:以查询账户信息时延时加载用户信息为例。
- 查询所有账户,同时获取账户所属用户名及其地址
1
2
3
4 > <select id="findAll" resultMap="accountMap">
> select * from account
> </select>
>
- 在dao层的Account映射文件添加association标签
1
2
3
4
5
6
7
8 > <resultMap id="accountMap" type="account">
> <id property="id" column="id"/>
> <result property="uid" column="uid"/>
> <result property="money" column="money"/>
> <!-- 从指定表方引用实体属性 -->
> <association property="user" column="uid" select="dao.IUserDao.findById" />
> </resultMap>
>
select:填写我们要调用的 select 映射的 id
column:填写我们要传递给 select 映射的参数
- association标签中调用的”dao.IUserDao.findById”
1
2
3
4 > <select id="findById" parameterType="INT" resultType="user">
> select * from user where id = #{uid}
> </select>
>
- 开启Mybatis的延迟加载策略
1
2
3
4
5 > <settings>
> <setting name="lazyLoadingEnabled" value="true"/>
> <setting name="aggressiveLazyLoading" value="false"/>
> </settings>
>
lazyLoadingEnabled
:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。
aggressiveLazyLoading
:当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载。
- 编写测试方法
1
2
3
4
5
6
7 > ...
> ...
>
> public void testFindAll(){
> List<Account> lists = accountDao.findAll();
> }
>
- 运行测试后的日志信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 > 开启延时加载:
> ==> Preparing: select * from account
> ==> Parameters:
> <== Total: 3
>
> 关闭延时加载:
> ==> Preparing: select * from account
> ==> Parameter
> ==> Preparing: select * from user where id = ?
> ==> Parameters: 41(Integer)
> <== Total: 1
> ==> Preparing: select * from user where id = ?
> ==> Parameters: 45(Integer)
> <== Total: 1
> <== Total: 3
>
通过collection实现延迟加载:以完成加载用户对象时,查询该用户所拥有的账户信息为例。
在dao层的User映射文件添加collection标签,其他步骤同association方法
1
2
3
4
5
6
7
8
9
10 > <resultMap type="user" id="userMap">
> <id column="id" property="id"/>
> <result column="username" property="username"/>
> <result column="address" property="address"/>
> <result column="sex" property="sex"/>
> <result column="birthday" property="birthday"/>
> <collection property="accounts" ofType="account"
> select="dao.IAccountDao.findByUid" column="id"> </collection>
> </resultMap>
>
<collection>
标签主要用于加载关联的集合对象
ofType
用于指定集合元素的数据类型
select
是用于指定查询账户的唯一标识(账户的dao全限定类名加上方法名称)
column
是用于指定使用哪个字段的值作为传递的条件查询
11. Mybatis缓存
1 | 像大多数的持久化框架一样,Mybatis也提供了缓存策略,通过缓存策略来减少数据库的查询次数,从而提高性能。 Mybatis中缓存分为一级缓存,二级缓存。 |
一级缓存:是SqlSession范围的缓存,当查询同一用户id的数据时,会优从一级缓存中查找数据,如果没有,再去数据库。
- 一级缓存的清空:当SqlSession执行flush、close、修改、添加、删除、commit等,或者执行
sqlSession.clearCache();
就会清空一级缓存。二级缓存:是mapper映射级别的缓存,多个SqlSession去操作同一个Mapper映射的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。
开启二级缓存:
在SqlMapConfig.xml文件中,开启二级缓存(已默认开启,这一步可省略)
1
2
3
4
5 > <settings>
> <!-- 开启二级缓存的支持,默认值为true,改为false代表不开启二级缓存 -->
> <setting name="cacheEnabled" value="true"/>
> </settings>
>
配置相关的Mapper映射文件
1
2
3
4
5 > <mapper namespace="dao.IUserDao">
> <!-- 开启二级缓存的支持 -->
> <cache/>
> </mapper>
>
配置statement上面的useCache属性
1
2
3
4 > <!-- 根据id查询 -->
> <select id="findById" resultType="user" parameterType="int" useCache="true"> select * from user where id = #{uid}
> </select>
>
注意事项
- 针对每次查询都需要最新的数据sql,要设置成useCache=false,禁用二级缓存。
- 使用二级缓存的类一定要实现java.io.Serializable接口,这样就可以使用序列化方式来保存对象。
12. 注解开发
@Insert:实现新增
@Update:实现更新
@Delete:实现删除
@Select:实现查询
@Result:实现结果集封装
1
2
3
4
5
6
7
8 > 代替了 <id>标签和<result>标签
> 中属性介绍:
> id 是否是主键字段
> column 数据库的列名
> property需要装配的属性名
> one 需要使用的 注解( (one= )()))
> many 需要使用的 注解( (many= )()))
>
- @Results:可以与@Result一起使用,封装多个结果集
1
2
3
4
5
6
7
8
9
10
11 > 代替的是标签<resultMap>
> "select * from user") (
> "userMap", value = { (id =
> true, column = "id", property = "userId"), (id =
> "username",property="userName"), (column=
> "sex",property="userSex"), (column=
> "address",property="userAddress"), (column=
> "birthday",property="userBirthday") (column=
> })
> List<User> findAll();
>
@ResultMap:实现引用@Results定义的封装
@One:实现一对一结果集封装
1
2
3
4
5
6 > 代替了<assocation>标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。
> "uid", property="user", (column=
> one="dao.IUserDao.findById", fetchType=FetchType.LAZY) ) (select=
> //select属性:代表将要执行的sql语句
> //fetchType属性:代表加载方式,一般如果要延迟加载都设置为LAZY的值
>
- @Many:实现一对多结果集封装
1
2
3
4 > 代替了<Collection>标签,是是多表查询的关键,在注解中用来指定子查询返回对象集合。
> "id",property="accounts", (column=
> many="dao.IAccountDao.findByUid", fetchType=FetchType.LAZY ) ) ( select=
>
@SelectProvider: 实现动态SQL映射
@CacheNamespace:实现注解二级缓存的使用
1
2
3 > true) //mybatis基于注解方式实现配置二级缓存 (blocking=
> public interface IUserDao {}
>
Spring
1. Spring概述
1 | Spring是Java SE/EE应用全栈轻量级开源框架,以IoC(Inverse Of Control:反转控制)和AOP(Aspect Oriented Programming:面向切面编程)为内核,提供了展现层Spring MVC和持久层Spring JDBC以及业务层事务管理等众多的企业级应用技术,还整合了众多著名第三方框架和类库,成为使用最多的Java EE企业应用开源框架。 |
2. 控制反转
1 | 控制反转(IoC)把创建对象的权利交给框架,是框架的重要特征,包括依赖注入和依赖查找。 |
1 | //模拟BeanFactory |
3. Spring环境配置
添加Spring环境依赖
1
2
3
4
5
6 > <dependency>
> <groupId>org.springframework</groupId>
> <artifactId>spring-context</artifactId>
> <version>5.0.2.RELEASE</version>
> </dependency>
>
在rescources根目录下创建Spring的XML约束,配置文件路径
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 >
> <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="accountService" class="service.impl.AccountServiceImpl">
> <!-- collaborators and configuration for this bean go here -->
> </bean>
>
> <bean id="accountDao" class="dao.impl.AccountDaoImpl">
> <!-- collaborators and configuration for this bean go here -->
> </bean>
>
> <!-- more bean definitions go here -->
>
> </beans>
>
测试配置是否成功
1
2
3
4
5
6
7
8 > public class Client{
> public static void main(String[] args){
> ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
> IAccountService aService = (IAccountService) ac.getBean("accountService");
> IAccountDao adao = ac.getBean("accountDao", IAccountDao.class);
> System.out.println(aService);
> System.out.println(aDao);}}
>
4. ApplicationContext
BeanFactory 和 ApplicationContext的区别
BeanFactory 是Spring 容器中的顶层接口,ApplicationContext 是它的子接口。
ApplicationContext:只要一读取配置文件,默认情况下就会创建对象。
BeanFactory:在使用的时候才创建对象。
ApplicationContext 接口的实现类
- ClassPathXmlApplicationContext:从类的根路径下加载配置文件(推荐使用)
- FileSystemXmlApplicationContext:从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置
- AnnotationConfigApplicationContext:可以读取注解的spring容器,用于注解配置的容器对象
5. bean标签
1 | 用于配置对象让spring来创建的,默认情况下它调用的是类中的无参构造函数。如果没有无参构造函数则不能创建成功。 |
属性:
- id:给对象在容器中提供一个唯一标识。用于获取对象。
- class:指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数。
- init-method:指定类中的初始化方法名称。
- destroy-method:指定类中销毁方法名称。
- scope:指定对象的作用范围。
- singleton:默认值,单例的
- prototype:多例的
- request:WEB项目中,Spring创建一个Bean的对象并存入到request域中
- session:WEB项目中,Spring创建一个Bean的对象并存入到session域中
- global session:WEB项目中,Spring创建一个Bean的对象并应用在Portlet环境
实例化的三种方式:
使用默认无参构造函数:如果bean中没有默认无参构造函数,将会创建失败。
<bean id="accountService" class="service.impl.AccountServiceImpl"/>
使用静态工厂的方法创建对象:
1
2
3
4 > public class StaticFactory {
> public static IAccountService createAccountService(){
> return new AccountServiceImpl(); } }
>
使用StaticFactory类中的静态方法createAccountService创建对象,并存入spring容器
<bean id="accountService"
class="factory.StaticFactory"
(指定静态工厂的全限定类名)
factory-method="createAccountService"></bean>
(指定生产对象的静态方法)
使用实例工厂的方法创建对象:
1
2
3
4 > public class InstanceFactory {
> public IAccountService createAccountService(){
> return new AccountServiceImpl(); } }
>
先把工厂的创建交给spring来管理,然后在使用工厂的bean来调用里面的方法
<bean id="instancFactory" class="factory.InstanceFactory"></bean>
<bean id="accountService"
factory-bean="instancFactory"
(用于指定实例工厂bean的id)
factory-method="createAccountService"></bean>
(用于指定实例工厂中创建对象的方法)
6. 依赖注入
1 | 依赖注入:Dependency Injection,是spring框架核心ioc的具体实现。使用spring之后,业务层和持久层的依赖关系由spring来维护,我们可以通过配置标签为变量注入值和属性。 |
构造函数注入
1
2
3
4
5
6
7 > <bean id="accountService" class="service.impl.AccountServiceImpl">
> <constructor-arg name="name" value="张三"></constructor-arg>
> <constructor-arg name="age" value="18"></constructor-arg>
> <constructor-arg name="birthday" ref="now"></constructor-arg>
> </bean>
> <bean id="now" class="java.util.Date"></bean>
>
涉及的标签:
constructor-arg
相关属性:
- index:指定参数在构造函数参数列表的索引位置
- type:指定参数在构造函数中的数据类型
- name:指定参数在构造函数中的名称,用于寻找赋值对象
- value:用于赋值,能赋基本数据类型和String类型
- ref:用于赋值,能赋其他bean类型,该bean类型必须在配置文件中配置过
set方法注入
1
2
3
4
5
6
7
8 > <!-- 在类中需要提供注入成员的set方法 -->
> <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
> <property name="name" value="test"></property>
> <property name="age" value="21"></property>
> <property name="birthday" ref="now"></property>
> </bean>
> <bean id="now" class="java.util.Date"></bean>
>
涉及的标签:
property
注入集合属性
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 > <!-- 注入集合数据 List结构可用标签array,list,set;Map结构可用标签map,entry,props,prop -->
> <bean id="accountService" class="service.impl.AccountServiceImpl">
> <!-- 在注入集合数据时,只要结构相同,标签可以互换 -->
> <!-- 注入list集合数据 -->
> <property name="myList">
> <list>
> <value>AAA</value>
> <value>BBB</value>
> <value>CCC</value>
> </list>
> </property>
> <!-- 注入Map数据 -->
> <property name="myMap">
> <map>
> <prop key="testA">aaa</prop>
> <prop key="testB">bbb</prop>
> </map>
> </property>
> <!-- 注入properties数据 -->
> <property name="myProps">
> <prop>
> <entry key="testA" value="aaa"></entry>
> <entry key="testB">
> <value>bbb</value>
> </entry>
> </prop>
> </property>
> </bean>
>
7. 基于XML配置的CRUD
配置文件 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
<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">
<!-- 配置Service -->
<bean id="accountService" class="service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean>
<bean id="accountDao" class="dao.impl.AccountDaoImpl">
<property name="runner" ref="runner"/>
</bean>
<!--配置QueryRunner-->
<bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
<!--注入数据源-->
<constructor-arg name="ds" ref="dataSource"/>
</bean>
<!-- 配置数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!--连接数据库的必备信息-->
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/eesy"/>
<property name="user" value="root"/>
<property name="password" value="root"/>
</bean>
</beans>持久层文件 AccountDaoImpl.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14public class AccountDaoImpl implements IAccountDao {
private QueryRunner runner; //由spring框架来赋值,需要set方法
public void setRunner(QueryRunner runner) {
this.runner = runner;
}
public List<Account> findAllAccount() {
try{
return runner.query("select * from account",
new BeanListHandler<Account>(Account.class));
}catch (Exception e) {
throw new RuntimeException(e);
}
}业务层文件 AccountServiceImpl.java
1
2
3
4
5
6
7
8
9
10public class AccountServiceImpl implements IAccountService {
private IAccountDao accountDao; //由spring框架来赋值,需要set方法
public void setAccountDao(IAccountDao accountDao) {
this.accountDao = accountDao;
}
public List<Account> findAllAccount() {
return accountDao.findAllAccount();
}测试文件 AccountServiceTest.java
1
2
3
4
5
6
7
8
9
10
11
12//@RunWith将Junit运行器替换成spring运行器,为了提供spring的容器
(SpringJUnit4ClassRunner.class)
//@ContextConfiguration指定spring配置文件的位置
"classpath:bean.xml") (locations =
public class AccountServiceTest {
private IAccountService as;
public void testFindAll() {
List<Account> accounts = as.findAllAccount();
for(Account account : accounts){
System.out.println(account);}}
8. 基于XML+注解的IoC配置
配置文件 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
<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"/>
<!--配置QueryRunner-->
<bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
<!--注入数据源-->
<constructor-arg name="ds" ref="dataSource"/>
</bean>
<!-- 配置数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!--连接数据库的必备信息-->
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/eesy"/>
<property name="user" value="root"/>
<property name="password" value="root"/>
</bean>
</beans>持久层文件 AccountDaoImpl.java
1
2
3
4
5
6
7
8
9
10
11"accountDao") (
public class AccountDaoImpl implements IAccountDao {
private QueryRunner runner;
public List<Account> findAllAccount() {
try{
return runner.query("select * from account",
new BeanListHandler<Account>(Account.class));
}catch (Exception e) {
throw new RuntimeException(e);}}业务层文件 AccountServiceImpl.java
1
2
3
4
5
6
7
8"accountService") (
public class AccountServiceImpl implements IAccountService {
private IAccountDao accountDao;
public List<Account> findAllAccount() {
return accountDao.findAllAccount();
}测试文件 AccountServiceTest.java
1
2
3
4
5
6
7
8
9
10(SpringJUnit4ClassRunner.class)
"classpath:bean.xml") (locations =
public class AccountServiceTest {
private IAccountService as;
public void testFindAll() {
List<Account> accounts = as.findAllAccount();
for(Account account : accounts){
System.out.println(account);}}
9. 基于纯注解的IoC配置
SpringConfiguration.java
1
2
3
4
5//指定当前类是一个配置类
"com") //指定spring在创建容器时要扫描的包 (
//导入其他的配置类 (JdbcConfig.class)
"classpath:jdbcConfig.properties") //指定properties文件的位置 (
public class SpringConfiguration {}JdbcConfig.java
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
29public class JdbcConfig {
"${jdbc.driver}") (
private String driver;
"${jdbc.url}") (
private String url;
"${jdbc.username}") (
private String username;
"${jdbc.password}") (
private String password;
//创建一个QueryRunner对象
"runner") (name=
"prototype") (
public QueryRunner createQueryRunner(DataSource dataSource){
return new QueryRunner(dataSource);
}
//创建数据源对象
"ds") (name=
public DataSource createDataSource(){
try {
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setDriverClass(driver);
ds.setJdbcUrl(url);
ds.setUser(username);
ds.setPassword(password);
return ds;
}catch (Exception e){
throw new RuntimeException(e);}}}持久层文件 AccountDaoImpl.java
1
2
3
4
5
6
7
8
9
10
11"accountDao") (
public class AccountDaoImpl implements IAccountDao {
private QueryRunner runner;
public List<Account> findAllAccount() {
try{
return runner.query("select * from account",
new BeanListHandler<Account>(Account.class));
}catch (Exception e) {
throw new RuntimeException(e);}}业务层文件 AccountServiceImpl.java
1
2
3
4
5
6
7
8"accountService") (
public class AccountServiceImpl implements IAccountService {
private IAccountDao accountDao;
public List<Account> findAllAccount() {
return accountDao.findAllAccount();
}测试文件 AccountServiceTest.java
1
2
3
4
5
6
7
8
9
10(SpringJUnit4ClassRunner.class)
//由.xml换成.class文件 (classes = SpringConfiguration.class)
public class AccountServiceTest {
private IAccountService as;
public void testFindAll() {
List<Account> accounts = as.findAllAccount();
for(Account account : accounts){
System.out.println(account);}}
10. IoC中的注解
用于创建对象
@Component
作用: 把资源让spring来管理。相当于在xml中配置一个bean。
属性: value:指定bean的id。如果不指定value属性,默认bean的id是当前类的类名。首字母小写。
衍生注解:@Controller,@Service,@Repository 作用属性都相同,提供更加明确的语义化
@Controller
一般用于表现层的注解
@Service
一般用于业务层的注解
@Repository
一般用于持久层的注解
用于注入数据
@Autowired
作用:可以注解在变量上,按照变量类型在spring容器中匹配后注入,set方法可以省略。它只能注入其他bean类型。当有多个类型匹配时,使用要注入的对象变量名称作为bean的id,在spring容器查找,找到了也可以注入成功,找不到就报错。
@Qualifier
作用:在自动按照类型注入的基础之上,再按照Bean的id注入。它在给字段注入时不能独立使用,必须和@Autowire一起使用;但是给方法参数注入时,可以独立使用。
属性:value:指定bean的id。
@Resource
作用: 直接按照Bean的id注入。它也只能注入其他bean类型。
属性: name:指定bean的id。(“name“不能省略)
@value
作用: 注入基本数据类型和String类型数据的。
属性: value:用于指定值。
用于改变作用范围
@Scope
作用: 指定bean的作用范围。
属性: value:指定范围的值。
取值:singleton,prototype,request,session,globalsession
生命周期相关
@PostConstruct
作用: 用于指定初始化方法。
@PreDestroy
作用: 用于指定销毁方法。
用于配置文件
@Configuration
作用: 用于指定当前类是一个spring配置类,当创建容器时会从该类上加载注解。
获取容器时需要使用AnnotationApplicationContext(有@Configuration注解的类.class)。
属性: value:用于指定配置类的字节码
@ComponentScan
作用:用于指定spring在初始化容器时要扫描的包。
属性:basePackages:用于指定要扫描的包。和该注解中的value属性作用一样。
@Bean
作用: 该注解只能写在方法上,表明使用此方法创建一个对象,并且放入spring容器。
属性: name:给当前@Bean注解方法创建的对象指定一个名称(即bean的id)。
@PropertySource
作用:用于加载.properties文件中的配置。例如我们配置数据源时,可以把连接数据库的信息写到properties配置文件中,就可以使用此注解指定properties配置文件的位置。
属性: value[]:用于指定properties文件位置。如果是在类路径下,需要写上classpath:
@Import
作用: 用于导入其他配置类,在引入其他配置类时,可以不用再写@Configuration注解。
属性: value[]:用于指定其他配置类的字节码。
用于整合Junit
@RunWith
@RunWith(SpringJUnit4ClassRunner.class)
作用:将Junit运行器替换成spring运行器,提供spring的容器
@ContextConfiguration
@ContextConfiguration(locations= {"classpath:bean.xml"})
作用:指定spring配置文件的位置
11. AOP
1 | AOP,全称是Aspect Oriented Programming,即面向切面编程。通过把程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对已有的方法进行增强。 |
相关术语:
Joinpoint(连接点):指被拦截到的点,在spring中指的是被拦截到的方法。
Pointcut(切入点):指被拦截后进行增强修改的Joinpoint。
Advice(通知/增强):拦截到Joinpoint之后所要做的事情就是通知。
通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。
Introduction(引介):在不修改类代码的前提下,引介可以在运行期为类动态地添加一些方法或Field。
Target(目标对象):代理的目标对象。
Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入。
Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类。
Aspect(切面):是切入点和通知(引介)的结合。
12. 基于XML的AOP配置
配置文件 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
<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">
<!-- 配置service对象 -->
<bean id="accountService" class="service.impl.AccountServiceImpl"/>
<!-- 配置Logger类 -->
<bean id="logger" class="utils.Logger"/>
<!-- 配置AOP -->
<aop:config>
<!-- 配置切入点表达式 -->
<aop:pointcut id="pt1" expression="execution(* service.impl.*.*(..) )"/>
<!-- 配置切面 -->
<aop:aspect id="logAdvice" ref="logger">
<!-- 配置通知类型,通知方法和切入点方法 -->
<aop:before method="before" pointcut-ref="pt1"/>
<aop:after-returning method="afterRunning" pointcut-ref="pt1"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="pt1"/>
<aop:after method="after" pointcut-ref="pt1"/>
</aop:aspect>
</aop:config>
</beans>
13. AOP配置中的标签
<aop:config>
:用于声明开始aop的配置<aop:pointcut>
:用于配置切入点表达式,指定对哪些类的哪些方法进行增强
- expression:用于定义切入点表达式
- id:用于给切入点表达式提供一个唯一标识
<aop:aspect>
:用于配置切面
- id:给切面提供一个唯一标识
- ref:引用配置好的通知类bean的id
<aop:before>
:用于配置前置通知,指定增强的方法在切入点方法之前执行<aop:after-returning>
:用于配置后置通知<aop:after-throwing>
:用于配置异常通知<aop:after>
:用于配置最终通知<aop:around>
:用于配置环绕通知,通常独立使用,可以手动控制增强代码的执行时机
- method:指定通知中方法的名称
- pointct:定义切入点表达式
- pointcut-ref:指定切入点表达式的引用
切入点表达式
1 | 表达式语法:execution([修饰符] 返回值类型 包名.类名.方法名(参数)) |
14. 环绕通知
1 | //spring框架为我们提供了一个接口:ProceedingJoinPoint,它可以作为环绕通知的方法参数,在环绕通知执行时,spring框架会为我们提供该接口的实现类对象,我们直接使用就行。 |
15. 基于注解的AOP配置
配置文件 bean.xml 导入context的空间名称
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 告知spring,在创建容器时要扫描的包 -->
<context:component-scan base-package="com.itheima"/>
<!-- 开启spring对注解AOP的支持 -->
<aop:aspectj-autoproxy/>
</beans>AccountServiceImpl.java 把资源使用注解配置
1
2
3
4
5"accountService") (
public class AccountServiceImpl implements IAccountService{
public void saveAccount() {
System.out.println("执行了保存");}}Logger.java 方式一:通知类使用注解配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17"logger") (
//把当前类声明为切面类
public class Logger {
"execution(* com.itheima.service.impl.*.*(..) )") (
private void pt1(){} //指定切入点表达式
"pt1()") //注意:千万别忘了写括号 (
public void before(){System.out.println("前置通知");}
"pt1()") (
public void afterRunning(){System.out.println("后置通知");}
"pt1()") (
public void afterThrowing(){System.out.println("异常通知");}
"pt1()") ((
public void after(){System.out.println("最终通知");}}Logger.java 方式二:通知类使用环绕注解配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14"logger") (
//把当前类声明为切面类
public class Logger {
"execution(* com.itheima.service.impl.*.*(..) )") (
public void transactionAround(ProceedingJoinPoint pjp) {
System.out.println("前置通知");
try {
pjp.proceed(); //执行切入点的方法
System.out.println("后置通知");
} catch (Throwable throwable) {
System.out.println("异常通知");
}finally {
System.out.println("最终通知");
}}}SpringConfiguration.java 配置后可完全删除xml文件
1
2
3
4
5
"com.itheima") (basePackages=
public class SpringConfiguration {
}基于纯注解的测试方法
1
2
3
4
5
6
7
8(SpringJUnit4ClassRunner.class)
(classes = SpringConfiguration.class)
public class Test01 {
private IAccountService accountService;
public void testAccount(){
accountService.saveAccount();}}
16. JdbcDaoSupport
1 | JdbcDaoSupport是spring框架为我们提供的一个类,该类中定义了一个JdbcTemplate对象,持久层实现类Dao通过继承该类可以直接获得JdbcTemplate对象。但是要想创建该对象,需要为其提供一个数据源:具体源码如下: |
通过让Dao继承JdbcDaoSupport的方式,只能用于基于XML的方式,注解用不了。
17. Spring中的事务控制
事务的隔离级别(isolation):
- READ_UNCOMMITTED
- READ_COMMITTED
- REPEATABLE_READ
- SERIALIZABLE
事务的传播行为(propagation):
- REQUIRED:如果当前没有事务,就创建一个;如果已存在,就加入这个事务中。(默认值)
- SUPPORTS:使用当前事务,如果当前没有事务,就以非事务方式执行
- MANDATORY:使用当前事务,如果当前没有事务,就抛出异常
- REQUERS_NEW:新建事务,如果当前有事务,把当前事务挂起
- NOT_SUPPORTED:以非事务方式执行操作,如果当前有事务,把当前事务挂起
- NEVER:以非事务方式执行操作,如果当前有事务,抛出异常
- NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行REQUIRED类操作
超时时间(timeout):
- 默认值是-1,没有超时限制。如果有值,以秒为单位进行设置
只读事务(read-only):
- 是否只读事务,查询时一般设置为只读
18. 基于XML的声明式事务控制
1 |
|
19. 基于注解的声明式事务控制
1 |
|
SpringMVC
1. SpringMVC概述
1 | SpringMVC是一种基于Java的实现MVC设计模型的请求驱动类型的轻量级Web框架,属于Spring FrameWork的后续产品,已经融合在Spring Web Flow里面。它通过一套注解,让一个简单的Java类成为处理请求的控制器,而无须实现任何接口,同时它还支持RESTful编程风格的请求。 |
2. SpringMVC快速入门
创建Maven工程,工程参数中添加键值对archetypeCatalog:internal,解决项目创建过慢的问题
web.xml 配置核心控制器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16<!-- 配置spring mvc的核心控制器 -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 配置初始化参数,用于读取SpringMVC的配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!-- 配置servlet的对象的创建时间点:应用加载时创建。 取值只能是非0正整数,表示启动顺序 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>SpringMVC.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
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 开启注解扫描 -->
<context:component-scan base-package="cn.itcast"/>
<!-- 视图解析器对象,拼接前缀和后缀,进行请求转发 -->
<bean id="internalResourceViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- 开启SpringMVC框架注解的支持 -->
<mvc:annotation-driven />
<!-- 设置所有静态资源不拦截 -->
<mvc:default-servlet-handler/>
</beans>HelloController.java 编写控制器
1
2
3
4
5
6
7
8
9
"/hello") (path =
public class HelloController {
"/world") (path =
public String sayHello(){
System.out.println("Hello StringMVC");
return "success";
}
}
3. SpringMVC组件
前端控制器(DispatcherServlet)
用户请求到达前端控制器,它就相当于mvc 模式中的c,dispatcherServlet 是整个流程控制的中心,由
它调用其它组件处理用户的请求,dispatcherServlet 的存在降低了组件之间的耦合性。处理器映射器(HandlerMapping)
HandlerMapping 负责根据用户请求找到Handler 即处理器,SpringMVC 提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
处理器(Handler)
开发中要编写的具体业务控制器。由DispatcherServlet 把用户请求转发到Handler。由Handler 对具体的用户请求进行处理。
处理器适配器(HandlerAdapter)
通过HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
视图解析器(ViewResolver)
View Resolver 负责将处理结果生成View 视图,View Resolver 首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View 视图对象,最后对View 进行渲染将处理结果通过页面展示给用户。
1 | 在SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为SpringMVC 的三大组件。 |
4. 请求参数的绑定
1 | SpringMVC绑定请求参数的过程是通过把表单提交请求参数,作为控制器中方法参数进行绑定的。 |
1 | "/findAccount") ( |
支持的数据类型
基本类型: 包括基本类型和String类型
要求参数名称必须和控制器中方法的形参名称保持一致。(严格区分大小写)
POJO类型参数: 包括实体类,以及关联的实体类
要求控制器方法的参数类型是POJO类型,并且表单中参数名称和POJO类的属性名称保持一致。
数组和集合类型参数: 包括List结构和Map结构的集合(包括数组)
- 第一种方式要求集合类型的请求参数必须在POJO中。在表单中请求参数名称要和POJO中集合属性名称相同。给List集合中的元素赋值,使用下标。 给Map集合中的元素赋值,使用键值对。
- 第二种方式要求接收的请求参数是json格式数据,需要借助一个注解实现。
5. 设置编码过滤器
post请求方式:在web.xml中配置一个过滤器
1 | <!--中文乱码过滤器--> |
get请求方式:修改tomcat的server.xml配置文件
1 | <Connector connectionTimeout="20000" port="8080" |
6. 常用注解:
@RequestMapping
1 | ({ElementType.METHOD, ElementType.TYPE}) |
出现位置:
- 类上:请求URL的第一级访问目录,不写的话相当于应用的根目录。写的话需要以/开头使URL可以按照模块化管理。
- 方法上:请求URL的第二级访问目录。
属性:
value:用于指定请求的URL,和path属性的作用是一样的。
method:用于指定请求的方式。
params:用于指定限制请求参数的条件。要求请求参数的key和value必须和配置的一模一样。例如:
1
2
3 > params = {"accountName"},表示请求参数必须有accountName
> params = {"moeny!100"},表示请求参数中money不能是100。
>
headers:用于指定限制请求消息头的条件。
jsp中的访问方式:
1
2
3
4
5
6
7 > <body>
> <!-- 第一种访问方式 -->
> <a href="${pageContext.request.contextPath}/account/findAccount"> 查询账户 </a>
> <!-- 第二种访问方式 -->
> <a href="account/findAccount">查询账户</a> <!-- 不要在访问URL前面加/ -->
> </body>
>
@RequestParam
1 | 作用:把请求中指定名称的参数给控制器中的形参赋值。 |
属性:
value:请求参数中的名称。
required:请求参数中是否必须提供此参数。默认值:true,表示必须提供,如果不提供将报错。
1
2
3 > <!-- requestParams注解的使用 -->
> <a href="springmvc/useRequestParam?name=test">requestParam注解</a>
>
1
2
3
4
5
6 > "/useRequestParam") (
> public String useRequestParam(@RequestParam("name")String username)){
> System.out.println(username); //运行结果,获取name=test
> return "success";
> }
>
@RequestBody
1 | 用于获取请求体内容。直接使用得到是key=value&key=value...结构的数据。get请求方式不适用。 |
属性:
required:是否必须有请求体。默认值是:true。当取值为true时,get请求方式会报错。如果取值为false,get请求得到是null。
1
2
3
4
5
6
7
8
9
10 > <!-- requestBody注解的使用 -->
> <!-- post请求jsp代码 -->
> <form action="springmvc/useRequestBody" method="post">
> 用户名称:<input type="text" name="username" ><br/>
> 用户密码:<input type="password" name="password" ><br/>
> 用户年龄:<input type="text" name="age" ><br/>
> <input type="submit" value="保存">
> <!-- get请求jsp代码 -->
> <a href="springmvc/useRequestBody?body=test">requestBody注解get请求</a>
>
1
2 > @RequestMapping("/useRequestBody") public String useRequestBody(@RequestBody(required=false) String body){ System.out.println(body); return "success"; }
>
@PathVaribale
1 | 用于绑定url中的占位符。例如:请求url中 /delete/{id},这个{id}就是url占位符。 |
1 | <!-- PathVaribale注解的使用 --> |
1 | "/usePathVariable/{id}") ( |
7. 返回值分类
字符串
controller方法返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址。
使用关键字的方式进行转发或者重定向:
转发:
return "forward:/WEB-INF/pages/success.jsp"
重定向:
return "redirect:/index.jsp"
注:如果是重定向到jsp页面,则jsp页面不能写在WEB-INF目录中,否则无法找到。
void
在controller方法形参上可以定义request和response,使用request或response指定响应结果:
使用request转向页面:
request.getRequestDispatcher("/WEBINF/pages/success.jsp").
forward(request, response);
通过response页面重定向:
response.sendRedirect("testRetrunString")
通过response指定响应结果:
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("json串");
ModelAndView
ModelAndView是SpringMVC为我们提供的一个对象,该对象中有两个方法,对象可以作为返回值。
1
2
3
4
5
6
7
8
9
10 > public ModelAndView testModelAndView() {
> ModelAndView mv = new ModelAndView();
> User user = new User("Eric", "123", 18);
> //addObject方法将参数封装到对象中,在页面上可以通过el表达式直接获取 ${user.username}
> mv.addObject("user", user);
> //setViewName用于设置逻辑视图名称,视图解析器会根据名称前往指定的视图
> mv.setViewName("success");
> return mv;
> }
>
8. ResponseBody响应json数据
使用JQuery进行异步请求时,DispatcherServlet会拦截到所有的资源,导致一个问题就是静态资源(img、css、js)也会被拦截到,从而不能被使用。需在springmvc.xml配置文件设置静态资源不过滤
1
2
3
4<!-- 设置静态资源不过滤 -->
<mvc:resources location="/css/" mapping="/css/**"/>
<mvc:resources location="/images/" mapping="/images/**"/>
<mvc:resources location="/js/" mapping="/js/**"/>response.jsp
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<head>
<title>Title</title>
<script src="js/jquery.min.js"></script>
<script>
// 页面加载,绑定单击事件
$(function(){
$("#btn").click(function(){
alert("hello btn");
$.ajax({
// 编写json格式,设置属性和值
url:"user/testAjax",
contentType:"application/json;charset=UTF-8",
data:'{"username":"hehe","password":"123","age":30}',
dataType:"json",
type:"post",
success:function(data){
// data服务器端响应的json的数据,进行解析
alert(data);
alert(data.username);
alert(data.password);
alert(data.age);
}});});});
</script>
</head>
<body>
<button id="btn">发送ajax的请求</button>
</body>UserController.java
1
2
3
4
5
6
7
8
9
10
11"/testAjax") (
public User testAjax(@RequestBody User user){
System.out.println("testAjax方法执行了...");
// 客户端发送ajax的请求,传的是json字符串,后端把json字符串封装到user对象中
System.out.println(user);
// 做响应,模拟查询数据库
user.setUsername("haha");
user.setAge(40);
// 做响应
return user;
}
Json字符串和JavaBean对象互相转换的过程中,需要使用jackson的jar包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
9. 实现文件上传
1 | /** |
1 | /** |
1 | /** |
1 | <%-- 文件上传jsp页面 --%> |
10. SpringMVC拦截器
1 | SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。它是AOP思想的具体应用。要自定义拦截器,要求必须实现:HandlerInterceptor接口。 |
过滤器和拦截器的区别
过滤器是servlet规范中的一部分,任何java web工程都可以使用。
拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能用。
过滤器在url-pattern中配置了/*之后,可以对所有要访问的资源拦截。
拦截器它是只会拦截访问的控制器方法,对jsp,html,css,image或者js是不会进行拦截的。
1 | /** |
SSM环境搭建
1. pom.xml引入坐标依赖
1 | <properties> |
2. 搭建项目骨架
创建domain目录,编写实体类
创建dao目录,编写dao接口,添加方法,通过注解配置sql语句
1
2
3
4
5
6
7
8
9
public interface AccountDao {
"select * from account") (
public List<Account> findAll();
"insert into account (name,money) values (#{name},#{money})") (
public void saveAccount(Account account);
}创建service目录,编写service接口和实现类
1
2
3
4
5
6
7
8
9
10
11
12
13"accountService") (
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public List<Account> findAll() {
return accountDao.findAll();
}
public void saveAccount(Account account) {
accountDao.saveAccount(account);
}
}
创建controller目录,在controller中注入service对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
"/account") (
public class AccountController {
AccountService accountService;
"/findAll") (
public ModelAndView findAll(ModelAndView mv) {
List<Account> accounts = accountService.findAll();
mv.addObject("accounts",accounts);
mv.setViewName("list");
return mv;
}
"/save") (
public void save(Account account, HttpServletRequest request,
HttpServletResponse response) throws IOException {
accountService.saveAccount(account);
response.sendRedirect(request.getContextPath() + "/account/findAll");
return;
}
}
3. applicationContext.xml
1 |
|
4. web.xml配置
1 |
|
5. springmvc.xml
1 |
|
SSM框架工具
1. PageHelper
1 | PageHelper是国内非常优秀的一款开源的mybatis分页插件,它支持基本主流与常用的数据库,例如mysql、 |
使用步骤
pom.xml 添加依赖:
1
2
3
4
5<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>最新版本</version>
</dependency>applicationContext.xml 配置拦截器插件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18<!--创建SqlSessionFactory工厂-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!-- 传入PageHelper的插件 -->
<property name="plugins">
<array>
<!-- 传入插件的对象 -->
<bean class="com.github.pagehelper.PageInterceptor">
<property name="properties">
<props>
<prop key="helperDialect">oracle</prop>
<prop key="reasonable">true</prop>
</props>
</property>
</bean>
</array>
</property>
</bean>helperDialect :分页插件会自动检测当前的数据库链接,自动选择合适的分页方式。 你可以配置
helperDialect 属性来指定分页插件使用哪种方言:oracle
,mysql
,mariadb
,sqlite
…reasonable:分页合理化参数,默认值为false 。当该参数设置为 true 时, pageNum<=0 时会查询第一页, pageNum>pages (超过总数时),会查询最后一页。默认false 时,直接根据参数进行查询。
OrdersController.java
1
2
3
4
5
6
7
8
9"/findAll.do") (
public ModelAndView findAll(int page, int pageSize) throws Exception {
ModelAndView mv = new ModelAndView();
List<Orders> orders = ordersService.findAll(page, pageSize);
PageInfo pageInfo = new PageInfo(orders);
mv.addObject("pageInfo",pageInfo);
mv.setViewName("orders-page-list");
return mv;
}OrderServiceImpl.java
1
2
3
4public List<Orders> findAll(int page, int pageSize) throws Exception {
PageHelper.startPage(page, pageSize);
return ordersDao.findAll();
}在你需要进行分页的 MyBatis 查询方法前调用PageHelper.startPage 静态方法即可,紧跟在这个方法后的第一个MyBatis 查询方法会被进行分页。
orders-page-list.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18<tbody>
<c:forEach items="${pageInfo.list}" var="orders">
<tr>
<td><input name="ids" type="checkbox"></td>
<td>${orders.id }</td>
<td>${orders.orderNum }</td>
<td>${orders.product.productName }</td>
<td>${orders.product.productPrice }</td>
<td>${orders.orderTimeStr }</td>
<td class="text-center">${orders.orderStatusStr }</td>
<td class="text-center">
<button type="button" class="btn bg-olive btn-xs">订单</button>
<button type="button" class="btn bg-olive btn-xs">详情</button>
<button type="button" class="btn bg-olive btn-xs">编辑</button>
</td>
</tr>
</c:forEach>
</tbody>
2. Spring Security
1 | Spring Security是Spring项目组中用来提供安全认证服务的框架。 |
使用步骤
pom.xml 添加依赖:
1
2
3
4
5
6
7
8
9
10
11
12<dependencies>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>5.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>5.0.1.RELEASE</version>
</dependency>
</dependencies>web.xml 配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-security.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>spring-security.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
45
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
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/security
http://www.springframework.org/schema/security/spring-security.xsd">
<!-- 配置不拦截的资源 -->
<security:http pattern="/login.jsp" security="none"/>
<security:http pattern="/failer.jsp" security="none"/>
<security:http pattern="/css/**" security="none"/>
<security:http pattern="/img/**" security="none"/>
<security:http pattern="/plugins/**" security="none"/>
<!--
配置具体的规则
auto-config="true" 不用自己编写登录的页面,框架提供默认登录页面
use-expressions="false" 是否使用SPEL表达式
-->
<security:http auto-config="true" use-expressions="false">
<!-- 配置具体的拦截的规则 pattern="请求路径的规则" access="访问系统的人,必须有ROLE_USER的角色" -->
<security:intercept-url pattern="/**" access="ROLE_USER,ROLE_ADMIN"/>
<!-- 定义跳转的具体的页面 -->
<security:form-login
login-page="/login.jsp"
login-processing-url="/login.do"
default-target-url="/index.jsp"
authentication-failure-url="/failer.jsp"
authentication-succcess-forward-url="/pages/main.jsp "
/>
<!-- 关闭跨域请求 -->
<security:csrf disabled="true"/>
<!-- 退出 -->
<security:logout invalidate-session="true" logout-url="/logout.do" logout-success-url="/login.jsp" />
</security:http>
<!-- 切换成数据库中的用户名和密码 -->
<security:authentication-manager>
<security:authentication-provider user-service-ref="userService">
<!-- 配置加密的方式 -->
<security:password-encoder ref="passwordEncoder"/>
</security:authentication-provider>
</security:authentication-manager>
<!-- 配置加密类 -->
<bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>
</beans>IUserService.java
1
2public interface IUserService extends UserDetailsService {
}UserServiceImpl.java
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
private IUserDao userDao;
public UserDetails loadUserByUsername(String username) {
UserInfo userInfo = null;
try {
userInfo = userDao.findByUsername(username);
} catch (Exception e) {
e.printStackTrace();
}
User user = new User(userInfo.getUsername(), "{noop}" + userInfo.getPassword(),
userInfo.getStatus() == 0 ? false : true, true, true, true,
getAuthority(userInfo.getRoles()));
return user;
}
//作用就是返回一个List集合,集合中装入的是角色描述
public List<SimpleGrantedAuthority> getAuthority(List<Role> roles) {
List<SimpleGrantedAuthority> list = new ArrayList<>();
for (Role role : roles) {
list.add(new SimpleGrantedAuthority("ROLE_" + role.getRoleName()));
}
return list;
}
3. 方法级权限控制
1 | 在服务器端我们可以通过Spring security提供的注解对方法来进行权限控制。Spring Security在方法的权限控制上支持三种类型的注解,JSR-250注解、@Secured注解和支持表达式的注解,这三种注解默认都是没有启用的,需要 |
1 | 配置文件 |