ssm框架

框架知识点总结

Mybatis

1. 框架概述

1
框架(Framework)是某种应用的半成品,是一组组件,供你选用完成你自己的系统。通过框架,可以将应用自身的设计和具体的实现技术解耦,这样,软件的研发将集中在应用的设计上,而不是具体的技术实现。框架一般处在低层应用平台(如J2EE)和高层业务逻辑之间的中间层。
1
MyBatis 是一款优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和POJOs映射成数据库中的记录,使开发者只需要关注sql语句本身,而不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。

2. Mybatis快速入门

  1. 在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>
>
  1. 编写持久层接口的映射文件XXXDao.xml

    • 创建位置:创建在resources文件中,但必须和持久层接口在相同的包中
    • 名称:必须以持久层接口名称命名文件名,扩展名是.xml
1
2
3
4
5
6
7
8
9
10
11
> <?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">
> <mapper namespace="dao.IUserDao">
> <!--配置查询所有-->
> <select id="findAll" resultType="domain.User">
> select * from user
> </select>
> </mapper>
>
  1. 编写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
> <?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">
> <!-- 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. 编写测试类
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. 在持久层接口中添加注解,不再需要持久层接口的映射文件

    1
    2
    3
    4
    5
    >    public interface IUserDao {
    > @Select("select * from user")
    > List<User> findAll();
    > }
    >
  1. 修改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
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
<?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">
<mapper namespace="dao.IUserDao">
<!-- resultMap配置数据库和实体类的映射,用于数据库和实体类名称不对应时 -->
<resultMap type="domain.User" id="userMap">
<id column="id" property="userId"/>
<result column="username" property="userName"/>
<result column="sex" property="userSex"/>
<result column="address" property="userAddress"/>
<result column="birthday" property="userBirthday"/>
</resultMap>
<!-- 根据id查找 -->
<select id="findById" resultMap="userMap">
select * from user where id = #{id}
</select>
<!-- 插入数据 -->
<insert id="saveUser" parameterType="domain.User">
<!-- 配置保存时获取插入的id -->
<selectKey keyColumn="id" keyProperty="id" resultType="int" >
select last_insert_id()
</selectKey>
insert into user(username,birthday,sex,address) VALUES (#{username},#{birthday},#{sex},#{address})
</insert>
<!-- 修改数据 -->
<update id="updateUser" parameterType="domain.User">
update user set username = #{username},birthday = #{birthday},sex = #{sex},address=#{address} where id = #{id}
</update>
<!-- 删除数据 -->
<delete id="deleteUser" parameterType="int">
delete from user where id = #{uid}
</delete>
<!-- 模糊匹配查询 -->
<select id="findByName" parameterType="String" resultMap="userMap">
select * from user where username like #{username} <!--'%${value}%'-->
</select>
</mapper>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//测试类
@Before
public void init() throws IOException {
in = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
session = factory.openSession();
userDao = session.getMapper(IUserDao.class);
}

@After
public void destroy(){
session.commit();
session.close();
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}

#{}与${}的区别:

  • #{}表示一个占位符号,通过实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换,可以有效防止sql注入。 接收简单类型值或pojo属性值。
  • ${} 表示拼接sql串,通过将parameterType传入的内容拼接在sql中且不进行jdbc类型转换,可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。

4. SqlMapConfig.xml配置文件

SqlMapConfig.xml中配置的内容和顺序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-properties(属性) 
--property
-settings(全局配置参数)
--setting
-typeAliases(类型别名)
--typeAliase
--package
-typeHandlers(类型处理器)
-objectFactory(对象工厂)
-plugins(插件)
-environments(环境集合属性对象)
--environment(环境子属性对象)
---transactionManager(事务管理)
---dataSource(数据源)
-mappers(映射器)
--mapper
--package
  • 自定义别名

    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分为三类:

  1. POOLED:使用连接池的数据源,MyBatis会创建PooledDataSource实例
  2. UNPOOLED:不使用连接池的数据源,MyBatis会创建UnpooledDataSource实例
  3. JNDI:使用JNDI实现的数据源,MyBatis会从JNDI服务上查找DataSource实例,然后返回使用
1
2
3
4
5
6
7
<!-- 配置数据源(连接池)信息 --> 
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>

当我们需要创建SqlSession对象并需要执行SQL语句时,MyBatis才会去调用dataSource对象来创建java.sql.Connection对象。也就是说,java.sql.Connection对象的创建一直延迟到执行SQL语句的时候。

6. Mybatis事务控制

1
2
3
Mybatis框架是对JDBC的封装,所以Mybatis框架的事务控制方式是用JDBC的setAutoCommit()方法来设置事务提交方式的。在连接池中取出的连接,都会调用connection.setAutoCommit(false)方法实现事务提交。通过设定
session = factory.openSession(true);
传入true参数,实现事务的自动提交,不用再进行手动提交了。

7. 动态sql语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- 抽取重复的语句代码片段 -->
<sql id="defaultSql">
select * from user
</sql>
<!-- 查询所有用户在id的集合之中 -->
<select id="findInIds" resultType="user" parameterType="queryvo">
<!-- select * from user where id in (1,2,3,4,5); -->
<include refid="defaultSql"></include>
<where>
<if test="ids != null and ids.size() > 0">
<foreach collection="ids" open="id in ( " close=")" item="uid" separator=",">
#{uid}
</foreach>
</if>
</where>
</select>

标签说明:

  • <Sql>:将重复的sql提取出来,使用时用<include>引用即可,最终达到sql重用的目的。
  • <where>:用于条件拼装
  • <if>:标签中test属性中写的是对象的属性名,不为空时加入sql条件语句
  • <foreach>:用于遍历集合,它的属性:
    • collection:代表要遍历的集合元素,注意编写时不要写#{}
    • open:代表语句的开始部分
    • close:代表结束部分
    • item:代表遍历集合的每个元素,生成的变量名
    • sperator:代表分隔符

8. 一对一查询

以Account表(账户表)关联User表(用户表)为例:

  1. 在Account类中加入User类的对象作为Account类的一个属性,并添加GetterSetter方法

  2. 在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>
    >
  1. 配置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表(账户表)为例:

  1. 在User类中加入Account类的对象作为User类的一个属性,并添加GetterSetter方法

  2. 在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>
    >
  1. 配置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. 查询所有账户,同时获取账户所属用户名及其地址
1
2
3
4
> <select id="findAll" resultMap="accountMap">
> select * from account
> </select>
>
  1. 在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 映射的参数

  1. association标签中调用的”dao.IUserDao.findById”
1
2
3
4
> <select id="findById" parameterType="INT" resultType="user">
> select * from user where id = #{uid}
> </select>
>
  1. 开启Mybatis的延迟加载策略
1
2
3
4
5
> <settings>
> <setting name="lazyLoadingEnabled" value="true"/>
> <setting name="aggressiveLazyLoading" value="false"/>
> </settings>
>

lazyLoadingEnabled

延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。

aggressiveLazyLoading

当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载。

  1. 编写测试方法
1
2
3
4
5
6
7
> @Before...
> @After...
> @Test
> public void testFindAll(){
> List<Account> lists = accountDao.findAll();
> }
>
  1. 运行测试后的日志信息:
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的。

  • 开启二级缓存:

    1. 在SqlMapConfig.xml文件中,开启二级缓存(已默认开启,这一步可省略)

      1
      2
      3
      4
      5
      >      <settings> 
      > <!-- 开启二级缓存的支持,默认值为true,改为false代表不开启二级缓存 -->
      > <setting name="cacheEnabled" value="true"/>
      > </settings>
      >
  1. 配置相关的Mapper映射文件

    1
    2
    3
    4
    5
    >      <mapper namespace="dao.IUserDao"> 
    > <!-- 开启二级缓存的支持 -->
    > <cache/>
    > </mapper>
    >
  1. 配置statement上面的useCache属性

    1
    2
    3
    4
    >      <!-- 根据id查询 --> 
    > <select id="findById" resultType="user" parameterType="int" useCache="true"> select * from user where id = #{uid}
    > </select>
    >
  • 注意事项

    1. 针对每次查询都需要最新的数据sql,要设置成useCache=false,禁用二级缓存。
    2. 使用二级缓存的类一定要实现java.io.Serializable接口,这样就可以使用序列化方式来保存对象。

12. 注解开发

  • @Insert:实现新增

  • @Update:实现更新

  • @Delete:实现删除

  • @Select:实现查询

  • @Result:实现结果集封装

1
2
3
4
5
6
7
8
> 代替了 <id>标签和<result>标签
> @Result中属性介绍:
> id 是否是主键字段
> column 数据库的列名
> property需要装配的属性名
> one 需要使用的@One注解(@Result(one=@One)()))
> many 需要使用的@Many注解(@Result(many=@many)()))
>
  • @Results:可以与@Result一起使用,封装多个结果集
1
2
3
4
5
6
7
8
9
10
11
> 代替的是标签<resultMap>
> @Select("select * from user")
> @Results(id = "userMap", value = {
> @Result(id = true, column = "id", property = "userId"),
> @Result(column="username",property="userName"),
> @Result(column="sex",property="userSex"),
> @Result(column="address",property="userAddress"),
> @Result(column="birthday",property="userBirthday")
> })
> List<User> findAll();
>
  • @ResultMap:实现引用@Results定义的封装

  • @One:实现一对一结果集封装

1
2
3
4
5
6
> 代替了<assocation>标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。
> @Result(column="uid", property="user",
> one=@One(select="dao.IUserDao.findById", fetchType=FetchType.LAZY) )
> //select属性:代表将要执行的sql语句
> //fetchType属性:代表加载方式,一般如果要延迟加载都设置为LAZY的值
>
  • @Many:实现一对多结果集封装
1
2
3
4
> 代替了<Collection>标签,是是多表查询的关键,在注解中用来指定子查询返回对象集合。
> @Result(column="id",property="accounts",
> many=@Many( select="dao.IAccountDao.findByUid", fetchType=FetchType.LAZY ) )
>
  • @SelectProvider: 实现动态SQL映射

  • @CacheNamespace:实现注解二级缓存的使用

    1
    2
    3
    >   @CacheNamespace(blocking=true)	//mybatis基于注解方式实现配置二级缓存 
    > 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
2
控制反转(IoC)把创建对象的权利交给框架,是框架的重要特征,包括依赖注入和依赖查找。
控制反转运用了工厂模式,在实际开发中我们可以把三层的对象都使用配置文件配置起来,当启动服务器应用加载的时候,让一个类中的方法通过读取配置文件,把这些对象创建出来并存起来。存储这些对象的map称之为容器;读取配置文件,创建和获取三层对象的类就是工厂。
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
//模拟BeanFactory
public class BeanFactory {
//定义一个Properties对象
private static Properties props;
//定义一个Map,用于存放我们要创建的对象。我们把它称之为容器
private static Map<String,Object> beans;
//使用静态代码块为Properties对象赋值
static {
try {
//实例化对象
props = new Properties();
//获取properties文件的流对象
InputStream in =
BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
props.load(in);
//实例化容器
beans = new HashMap<String,Object>();
//取出配置文件中所有的Key
Enumeration keys = props.keys();
//遍历枚举
while (keys.hasMoreElements()){
//取出每个Key
String key = keys.nextElement().toString();
//根据key获取value
String beanPath = props.getProperty(key);
//反射创建对象
Object value = Class.forName(beanPath).newInstance();
//把key和value存入容器中,容器里面放的是对象!
beans.put(key,value);
}
}catch(Exception e){
throw new ExceptionInInitializerError("初始化properties失败!");
}
}
/**
* 根据bean的名称获取对象
* @param beanName
* @return
*/
public static Object getBean(String beanName){
return beans.get(beanName);
}
}

3. Spring环境配置

  1. 添加Spring环境依赖

    1
    2
    3
    4
    5
    6
    >    <dependency>
    > <groupId>org.springframework</groupId>
    > <artifactId>spring-context</artifactId>
    > <version>5.0.2.RELEASE</version>
    > </dependency>
    >
  1. 在rescources根目录下创建Spring的XML约束,配置文件路径

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    >    <?xml version="1.0" encoding="UTF-8"?>
    > <beans xmlns="http://www.springframework.org/schema/beans"
    > xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    > xsi:schemaLocation="http://www.springframework.org/schema/beans
    > http://www.springframework.org/schema/beans/spring-beans.xsd">
    >
    > <bean id="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. 测试配置是否成功

    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环境

实例化的三种方式:

  1. 使用默认无参构造函数:如果bean中没有默认无参构造函数,将会创建失败。

    <bean id="accountService" class="service.impl.AccountServiceImpl"/>

  2. 使用静态工厂的方法创建对象:

    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. 使用实例工厂的方法创建对象:

    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
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 配置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
    14
    public class AccountDaoImpl implements IAccountDao {
    private QueryRunner runner; //由spring框架来赋值,需要set方法
    public void setRunner(QueryRunner runner) {
    this.runner = runner;
    }
    @Override
    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
    10
    public 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的容器
    @RunWith(SpringJUnit4ClassRunner.class)
    //@ContextConfiguration指定spring配置文件的位置
    @ContextConfiguration(locations = "classpath:bean.xml")
    public class AccountServiceTest {
    @Autowired
    private IAccountService as;
    @Test
    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
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">

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

    <!--配置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
    @Repository("accountDao")
    public class AccountDaoImpl implements IAccountDao {
    @Autowired
    private QueryRunner runner;
    @Override
    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
    @Service("accountService")
    public class AccountServiceImpl implements IAccountService {
    @Autowired
    private IAccountDao accountDao;
    @Override
    public List<Account> findAllAccount() {
    return accountDao.findAllAccount();
    }
  • 测试文件 AccountServiceTest.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = "classpath:bean.xml")
    public class AccountServiceTest {
    @Autowired
    private IAccountService as;
    @Test
    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
    @Configuration	//指定当前类是一个配置类
    @ComponentScan("com") //指定spring在创建容器时要扫描的包
    @Import(JdbcConfig.class) //导入其他的配置类
    @PropertySource("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
    29
    public class JdbcConfig {
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;

    //创建一个QueryRunner对象
    @Bean(name="runner")
    @Scope("prototype")
    public QueryRunner createQueryRunner(DataSource dataSource){
    return new QueryRunner(dataSource);
    }

    //创建数据源对象
    @Bean(name="ds")
    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
    @Repository("accountDao")
    public class AccountDaoImpl implements IAccountDao {
    @Autowired
    private QueryRunner runner;
    @Override
    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
    @Service("accountService")
    public class AccountServiceImpl implements IAccountService {
    @Autowired
    private IAccountDao accountDao;
    @Override
    public List<Account> findAllAccount() {
    return accountDao.findAllAccount();
    }
  • 测试文件 AccountServiceTest.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = SpringConfiguration.class) //由.xml换成.class文件
    public class AccountServiceTest {
    @Autowired
    private IAccountService as;
    @Test
    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
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- 配置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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
表达式语法:execution([修饰符] 返回值类型 包名.类名.方法名(参数)) 
写法说明:
全匹配方式:
public void service.impl.AccountServiceImpl.saveAccount(domain.Account)
访问修饰符可以省略
void service.impl.AccountServiceImpl.saveAccount(domain.Account)
返回值可以使用*号,表示任意返回值
* service.impl.AccountServiceImpl.saveAccount(domain.Account)
包名可以使用*号,表示任意包,但是有几级包,需要写几个
* *.*.AccountServiceImpl.saveAccount(domain.Account)
使用..来表示当前包,及其子包
* service..AccountServiceImpl.saveAccount(domain.Account)
类名可以使用*号,表示任意类
* service..*.saveAccount(domain.Account)
方法名可以使用*号,表示任意方法
* service..*.*(domain.Account)
参数列表可以使用*,表示参数可以是任意数据类型,但是必须有参数
* service..*.*(*)
参数列表可以使用..表示有无参数均可,有参数可以是任意类型
* service..*.*(..)
全通配方式
* *..*.*(..)
注: 通常情况下,我们都是对业务层的方法进行增强,所以切入点表达式都是切到业务层实现类。
execution(* service.impl.*.*(..))

14. 环绕通知

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//spring框架为我们提供了一个接口:ProceedingJoinPoint,它可以作为环绕通知的方法参数,在环绕通知执行时,spring框架会为我们提供该接口的实现类对象,我们直接使用就行。
public Object transactionAround(ProceedingJoinPoint pjp) {
Object rtValue = null; //定义返回值
try {
Object[] args = pjp.getArgs(); //获取方法执行所需的参数
beginTransaction(); //前置通知:开启事务
rtValue = pjp.proceed(args); //执行方法
commit(); //后置通知:提交事务
}catch(Throwable e) {
rollback(); //异常通知:回滚事务
e.printStackTrace(); }
finally {
release(); } //最终通知:释放资源
return rtValue; }

15. 基于注解的AOP配置

  • 配置文件 bean.xml 导入context的空间名称

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <?xml version="1.0" encoding="UTF-8"?>
    <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
    @Service("accountService")
    public class AccountServiceImpl implements IAccountService{
    @Override
    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
    @Component("logger")
    @Aspect //把当前类声明为切面类
    public class Logger {
    @Pointcut("execution(* com.itheima.service.impl.*.*(..) )")
    private void pt1(){} //指定切入点表达式

    @Before("pt1()") //注意:千万别忘了写括号
    public void before(){System.out.println("前置通知");}

    @AfterReturning("pt1()")
    public void afterRunning(){System.out.println("后置通知");}

    @AfterThrowing("pt1()")
    public void afterThrowing(){System.out.println("异常通知");}

    @After(("pt1()")
    public void after(){System.out.println("最终通知");}}
  • Logger.java 方式二:通知类使用环绕注解配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    @Component("logger")
    @Aspect //把当前类声明为切面类
    public class Logger {
    @Around("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
    @Configuration
    @ComponentScan(basePackages="com.itheima")
    @EnableAspectJAutoProxy
    public class SpringConfiguration {
    }
  • 基于纯注解的测试方法

    1
    2
    3
    4
    5
    6
    7
    8
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = SpringConfiguration.class)
    public class Test01 {
    @Autowired
    private IAccountService accountService;
    @Test
    public void testAccount(){
    accountService.saveAccount();}}

16. JdbcDaoSupport

1
2
3
4
5
6
7
8
9
10
11
12
13
JdbcDaoSupport是spring框架为我们提供的一个类,该类中定义了一个JdbcTemplate对象,持久层实现类Dao通过继承该类可以直接获得JdbcTemplate对象。但是要想创建该对象,需要为其提供一个数据源:具体源码如下:
public abstract class JdbcDaoSupport extends DaoSupport {
//定义对象
private JdbcTemplate jdbcTemplate;
//set方法注入数据源,判断是否注入了,注入了就创建JdbcTemplate
public final void setDataSource(DataSource dataSource) {
if (this.jdbcTemplate == null || dataSource != this.jdbcTemplate.getDataSource()) { //如果提供了数据源就创建JdbcTemplate
this.jdbcTemplate = createJdbcTemplate(dataSource);
initTemplateConfig(); } }
//使用数据源创建JdcbTemplate
protected JdbcTemplate createJdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}

通过让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
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
46
47
48
49
50
51
52
53
54
55
56
<?xml version="1.0" encoding="UTF-8"?>
<!-- 导入aop和tx两个名称空间 -->
<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"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">

<!-- 配置service -->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean>

<!-- 配置dao -->
<bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>

<!-- 配置数据源 -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/eesy" />
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>

<!-- 配置一个事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>

<!-- 事务的配置 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- 配置事务的属性 -->
<tx:attributes>
<tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="*" propagation="REQUIRED" read-only="false"/>
</tx:attributes>
</tx:advice>

<!-- 配置AOP切入点表达式 -->
<aop:config>
<aop:pointcut id="pt1"
expression="execution(* com.itheima.service.impl.*.*(..))"/>
<!-- 建立事务的通知和切入点表达式的关系 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"/>
</aop:config>
</beans>

19. 基于注解的声明式事务控制

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
46
47
<?xml version="1.0" encoding="UTF-8"?>
<!-- 导入context和tx两个名称空间 -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
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/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">

<!-- 告知spring,在创建容器时要扫描的包 -->
<context:component-scan base-package="com.itheima"/>

<!-- 配置jdbcTemplate -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>

<!-- 配置数据源 -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/eesy" />
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>

<!-- 配置一个事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>

<!-- 开启spring对注解事务的支持 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

<!-- 在业务层需要的地方使用@Transactional注解 -->
@Transactional注解可以出现在接口上,类上和方法上。
出现接口上,表示该接口的所有实现类都有事务支持。
出现在类上,表示类中所有方法有事务支持。
出现在方法上,表示方法有事务支持。
以上三个位置的优先级:方法>类>接口

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
    <?xml version="1.0" encoding="UTF-8"?>
    <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
    @Controller
    @RequestMapping(path = "/hello")
    public class HelloController {
    @RequestMapping(path = "/world")
    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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
在SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为SpringMVC 的三大组件。
在SpringMVC.xml配置文件中使用<mvc:annotation-driven>注解可替代处理器映射器和处理器适配器的配置。
相当于在xml 中配置了:
<!-- Begin -->
<!-- HandlerMapping -->
<beanclass="org.springframework.web.servlet.mvc.method.annotation.
RequestMappingHandlerMapping"></bean>
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean> <!-- HandlerAdapter -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.
RequestMappingHandlerAdapter"></bean>
<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"></bean>
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean> <!-- HadnlerExceptionResolvers -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.
ExceptionHandlerExceptionResolver"></bean>
<bean class="org.springframework.web.servlet.mvc.annotation.
ResponseStatusExceptionResolver"></bean>
<bean class="org.springframework.web.servlet.mvc.support.
DefaultHandlerExceptionResolver"></bean>
<!-- End -->

4. 请求参数的绑定

1
2
SpringMVC绑定请求参数的过程是通过把表单提交请求参数,作为控制器中方法参数进行绑定的。
<a href="account/findAccount?accountId=10">查询账户</a>
1
2
3
4
@RequestMapping("/findAccount") 
public String findAccount(Integer accountId) {
System.out.println("查询了账户"+accountId); //自动获取到accountId=10
return "success"; }

支持的数据类型

  • 基本类型: 包括基本类型和String类型

    要求参数名称必须和控制器中方法的形参名称保持一致。(严格区分大小写)

  • POJO类型参数: 包括实体类,以及关联的实体类

    要求控制器方法的参数类型是POJO类型,并且表单中参数名称和POJO类的属性名称保持一致。

  • 数组和集合类型参数: 包括List结构和Map结构的集合(包括数组)

    1. 第一种方式要求集合类型的请求参数必须在POJO中。在表单中请求参数名称要和POJO中集合属性名称相同。给List集合中的元素赋值,使用下标。 给Map集合中的元素赋值,使用键值对。
    2. 第二种方式要求接收的请求参数是json格式数据,需要借助一个注解实现。

5. 设置编码过滤器

post请求方式:在web.xml中配置一个过滤器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!--中文乱码过滤器-->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<!-- 过滤所有请求 -->
<url-pattern>/*</url-pattern>
</filter-mapping>

get请求方式:修改tomcat的server.xml配置文件

1
2
3
<Connector connectionTimeout="20000" port="8080" 
protocol="HTTP/1.1" redirectPort="8443"
URIEncoding="UTF-8"/> <!-- 添加URIEncoding参数 -->

6. 常用注解:

@RequestMapping

1
2
3
@Target({ElementType.METHOD, ElementType.TYPE}) 
@Retention(RetentionPolicy.RUNTIME)
用于建立请求URL和处理请求方法之间的对应关系

出现位置:

  • 类上:请求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
>   @RequestMapping("/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
2
用于绑定url中的占位符。例如:请求url中 /delete/{id},这个{id}就是url占位符。 
url支持占位符是spring3.0之后加入的。是springmvc支持rest风格URL的一个重要标志。
1
2
<!-- PathVaribale注解的使用 --> 
<a href="springmvc/usePathVariable/100">pathVariable注解</a>
1
2
3
4
@RequestMapping("/usePathVariable/{id}") 
public String usePathVariable(@PathVariable("id") Integer id){
System.out.println(id);
return "success"; }

7. 返回值分类

字符串

  1. controller方法返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址。

  2. 使用关键字的方式进行转发或者重定向:

    转发:return "forward:/WEB-INF/pages/success.jsp"

    重定向:return "redirect:/index.jsp"

    注:如果是重定向到jsp页面,则jsp页面不能写在WEB-INF目录中,否则无法找到。

void

在controller方法形参上可以定义request和response,使用request或response指定响应结果:

  1. 使用request转向页面:request.getRequestDispatcher("/WEBINF/pages/success.jsp").

    forward(request, response);

  2. 通过response页面重定向:response.sendRedirect("testRetrunString")

  3. 通过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数据

  1. 使用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/**"/>
  2. 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>
  3. UserController.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @RequestMapping("/testAjax")
    public @ResponseBody 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;
    }
  1. 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
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
/**
* 传统文件上传
* @return
*/
@RequestMapping("/fileupload1")
public String fileuoload1(HttpServletRequest request) throws Exception {
System.out.println("文件上传...");
// 使用fileupload组件完成文件上传
String path = request.getSession().getServletContext().getRealPath("/uploads/");
// 判断,该路径是否存在
File file = new File(path);
if(!file.exists()){
// 创建该文件夹
file.mkdirs();
}
// 解析request对象,获取上传文件项
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
// 解析request
List<FileItem> items = upload.parseRequest(request);
// 遍历
for(FileItem item:items){
// 进行判断,当前item对象是否是上传文件项
if(item.isFormField()){
// 说明普通表单向
}else{
// 说明上传文件项,获取上传文件的名称
String filename = item.getName();
// 把文件的名称设置唯一值,uuid
String uuid = UUID.randomUUID().toString().replace("-", "");
filename = uuid+"_"+filename;
// 完成文件上传
item.write(new File(path,filename));
// 删除临时文件
item.delete();}}
return "success";
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* SpringMVC文件上传
* @return
*/
@RequestMapping("/fileupload2")
public String fileuoload2(HttpServletRequest request, MultipartFile upload) throws Exception {
System.out.println("springmvc文件上传...");
// 使用fileupload组件完成文件上传
String path = request.getSession().getServletContext().getRealPath("/uploads/");
// 判断,该路径是否存在
File file = new File(path);
if(!file.exists()){
// 创建该文件夹
file.mkdirs();
}
// 说明上传文件项,获取上传文件的名称
String filename = upload.getOriginalFilename();
// 把文件的名称设置唯一值,uuid
String uuid = UUID.randomUUID().toString().replace("-", "");
filename = uuid+"_"+filename;
// 完成文件上传
upload.transferTo(new File(path,filename));
return "success";
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* 跨服务器文件上传
* @return
*/
@RequestMapping("/fileupload3")
public String fileuoload3(MultipartFile upload) throws Exception {
System.out.println("跨服务器文件上传...");
// 定义上传文件服务器路径
String path = "http://localhost:9090/uploads/";
// 说明上传文件项,获取上传文件的名称
String filename = upload.getOriginalFilename();
// 把文件的名称设置唯一值,uuid
String uuid = UUID.randomUUID().toString().replace("-", "");
filename = uuid+"_"+filename;
// 创建客户端的对象
Client client = Client.create();
// 和图片服务器进行连接
WebResource webResource = client.resource(path + filename);
// 上传文件
webResource.put(upload.getBytes());
return "success";
}
1
2
3
4
5
6
<%-- 文件上传jsp页面 --%>
<h3>Springmvc文件上传</h3>
<form action="/user/fileupload2" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="upload"/><br/>
<input type="submit" value="上传" />
</form>

10. SpringMVC拦截器

1
SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。它是AOP思想的具体应用。要自定义拦截器,要求必须实现:HandlerInterceptor接口。

过滤器和拦截器的区别

过滤器是servlet规范中的一部分,任何java web工程都可以使用。

拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能用。

过滤器在url-pattern中配置了/*之后,可以对所有要访问的资源拦截。

拦截器它是只会拦截访问的控制器方法,对jsp,html,css,image或者js是不会进行拦截的。

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
/**
* 自定义拦截器
*/
public class MyInterceptor1 implements HandlerInterceptor{
/**
* 预处理,controller方法执行前
* return true 放行,执行下一个拦截器,如果没有,执行controller中的方法
* return false不放行
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
System.out.println("MyInterceptor1执行了...");
return true;
}
/**
* 后处理方法,controller方法执行后,success.jsp执行之前
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor1执行了...后1111");
}
/**
* success.jsp页面执行后,该方法会执行
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
System.out.println("MyInterceptor1执行了...");
}
}

SSM环境搭建

1. pom.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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
  <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring.version>5.0.2.RELEASE</spring.version>
<slf4j.version>1.6.6</slf4j.version>
<log4j.version>1.2.12</log4j.version>
<mysql.version>5.1.6</mysql.version>
<mybatis.version>3.4.5</mybatis.version>
</properties>

<dependencies>
<!-- spring -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.8</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>compile</scope>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>

<!-- log start -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>

<!-- log end -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>

<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>

<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
</dependencies>

2. 搭建项目骨架

  • 创建domain目录,编写实体类

  • 创建dao目录,编写dao接口,添加方法,通过注解配置sql语句

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Repository
    public interface AccountDao {

    @Select("select * from account")
    public List<Account> findAll();

    @Insert("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
    @Service("accountService")
    public class AccountServiceImpl implements AccountService {
    @Autowired
    private AccountDao accountDao;
    @Override
    public List<Account> findAll() {
    return accountDao.findAll();
    }
    @Override
    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
    @Controller
    @RequestMapping("/account")
    public class AccountController {
    @Autowired
    AccountService accountService;
    @RequestMapping("/findAll")
    public ModelAndView findAll(ModelAndView mv) {
    List<Account> accounts = accountService.findAll();
    mv.addObject("accounts",accounts);
    mv.setViewName("list");
    return mv;
    }
    @RequestMapping("/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
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
46
47
48
49
50
51
52
53
54
<?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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">

<!--开启注解的扫描,只扫描service-->
<context:component-scan base-package="cn.itcast.service.impl"/>

<!--在spring中整合mybatis框架-->
<!--配置连接池-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql:///ssm"/>
<property name="user" value="root"/>
<property name="password" value="root"/>
</bean>
<!--创建SqlSessionFactory工厂-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--配置AccountDao接口所在包-->
<bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="cn.itcast.dao"/>
</bean>

<!--配置spring框架声明式事务管理-->
<!--配置事务管理器-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="find*" read-only="true" propagation="SUPPORTS"/>
<tx:method name="*" />
</tx:attributes>
</tx:advice>
<!--配置AOP增强-->
<aop:config>
<aop:advisor advice-ref="txAdvice"
pointcut="execution(* cn.itcast.service.impl.*.*(..))"/>
</aop:config>
</beans>

4. web.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
46
47
48
49
50
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
<display-name>Archetype Created Web Application</display-name>
<!--配置前端控制器-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--加载springmvc.xml配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!--启动服务器,创建该servlet-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

<!--解决中文乱码的过滤器-->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<!--配置spring的监听器-->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>

<!--设置spring配置文件的路径-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
</web-app>

5. 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
26
27
28
29
30
31
<?xml version="1.0" encoding="UTF-8"?>
<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">

<!--开启注解扫描,只扫描Controller注解-->
<context:component-scan base-package="cn.itcast">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller" />
</context:component-scan>

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

<!-- 设置静态资源不过滤 -->
<mvc:default-servlet-handler/>

<!--开启SpringMVC注解的支持-->
<mvc:annotation-driven/>
</beans>

SSM框架工具

1. PageHelper

1
2
PageHelper是国内非常优秀的一款开源的mybatis分页插件,它支持基本主流与常用的数据库,例如mysql、
oracle、mariaDB、DB2、SQLite、Hsqldb等。

使用步骤

  • 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 属性来指定分页插件使用哪种方言:oraclemysqlmariadbsqlite

    reasonable:分页合理化参数,默认值为false 。当该参数设置为 true 时, pageNum<=0 时会查询第一页, pageNum>pages (超过总数时),会查询最后一页。默认false 时,直接根据参数进行查询。

  • OrdersController.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @RequestMapping("/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
    4
    public 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
    <?xml version="1.0" encoding="UTF-8"?>
    <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
    2
    public 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
    @Autowired
    private IUserDao userDao;

    @Override
    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
2
在服务器端我们可以通过Spring security提供的注解对方法来进行权限控制。Spring Security在方法的权限控制上支持三种类型的注解,JSR-250注解、@Secured注解和支持表达式的注解,这三种注解默认都是没有启用的,需要
单独通过global-method-security元素的对应属性进行启用。
1
2
3
4
5
6
7
8
配置文件
<security:global-method-security jsr250-annotations="enabled"/>
<security:global-method-security secured-annotations="enabled"/>
<security:global-method-security pre-post-annotations="disabled"/>
注解开启
@EnableGlobalMethodSecurity :Spring Security默认是禁用注解的,要想开启注解,需要在继承
WebSecurityConfigurerAdapter的类上加@EnableGlobalMethodSecurity注解,并在该类中将
AuthenticationManager定义为Bean。