标题:Java Web(SSM框架)知识点梳理复习
作者:Aristochi
字数统计:10068
更新时间: 2020/01/20 18:16
参考书目:Java EE框架整合开发入门到实战——Spring+Spring MVC+MyBatis
部分内容引自 w3cschool的spring教程
篇幅限制,Mybatis一对多示例代码在另一篇笔记
有很多图片上传太麻烦了(有点点懒),可以看我的有道云笔记:Java Web(SSM框架)知识点梳理复习
一个借鉴其他项目修改的小图书电商的SSM项目,项目框架(Spring+SpringMVC+Mybatis+Maven)
复习提纲
第一部分 Spring
第1章 Spring入门
Spring核心容器中有哪些模块?P3
① Spring-core
spring-core模块提供了框架的基本组成部分,包括 IoC(控制反转) 和依赖注入功能。
② Spring-beans
spring-beans 模块提供 BeanFactory,工厂模式的经典实现,Spring将管理对象称为Bean
③ Spring-context
建立在core和 beans 模块的基础上,提供一个框架式的对象访问方式,是访问定义和配置的任何对象的媒介。ApplicationContext接口是Context模块的焦点
④ Spring-context-support
spring-context-support支持整合第三方库到Spring应用程序上下文,比如缓存(EhCache, Guava, JCache)、任务调度(CommonJ, Quartz)、模板引擎(FreeMarker, JasperReports, Velocity)等。
⑤ Spring-expression
spring-expression模块提供了强大的表达式语言,用于在运行时查询和操作对象图。它是JSP2.1规范中定义的统一表达式语言的扩展,支持set和get属性值、属性赋值、方法调用、访问数组集合及索引的内容、逻辑算术运算、命名变量、通过名字从Spring IoC容器检索对象,还支持列表的投影、选择以及聚合等。
完整依赖关系如下图:
第二章 SpringIOC
2.1 SpringIOC的基本概念
1. Spring框架中,什么是控制反转?什么是依赖注入?有何区别?
-
控制反转:当某个对象(调用者)需要另外一个对象(被调用者)时,传统的编程模式下,调用者通常会new一个被调用者对象。在Spring中,对象不再由调用者创建,而是由Spring容器来创建。Spring负责控制程序之间的依赖关系,而不是由调用者控制,这样,控制权由调用者转移到Spring容器,控制权发生的反转,这就是Spring的控制反转。
-
依赖注入:从应用程序角度来看,调用者依赖Spring容器创建并注入它所需要的被调用者对象,这就是依赖注入。
-
区别:依赖反转和依赖注入其实是对同一件事情在不同角度的不同表述,依赖注入是从应用程序的角度在描述,而控制反转是从容器的角度在描述。
2.2 Spring IoC容器
- Spring IoC容器的设计主要是基于BeanFactory和ApplicationContext两个接口
- 创建ApplicationContext接口实例通常有三种方法:
-
通过ClassPathXmlApplicationContext创建
-
通过FileSystemXmlApplicationContext创建
-
通过web服务器实例化ApplicationContext容器
2.3 依赖注入的类型
依赖注入的类型包括:使用构造方法注入,使用属性的setter方法注入
第3章Spring Bean
3.2 Bean的实例化:构造方法实例化,静态工厂实例化,实例工厂实例化
在Spring框架中,Spring容器可以调用Bean对应类中构造方法来实例化Bean,这种方式称为构造方法实例化。说明:使用构造方法注入,添加有参构造方法时,切记先添加无参构造。
使用静态工厂实例化Bean时,要求开发者在工厂类中创建一个静态方法来创建Bean的实例。配置Bean时,class属性指定静态工厂类,同时还需要使用factory-method属性指定工厂类中的静态方法。
为什么需要工厂模式:有些对象不能够通过反射直接创建(抽象类和接口等)
实质:就是类名.静态方法
使用实例工厂实例化Bean时,要求开发者在工厂类中创建一个实例方法来创建Bean的实例。配置Bean时,需要使用factory-bean属性指定配置的实例工厂,同时还需要factory-method属性指定实例工厂中的实例方法。
Spring如何创建对象,对象是如何存储的,用户是如何获取对象的?
-
Spring容器启动时,首先会加载Spring的核心配置文件,Spring容器逐行进行解析xml配置文件
-
当解析到bean标签时开始创建对象,根据class属性中的数据通过反射机制创建对象。
-
将创建好的对象存入Spring所维护的Map<key,value>中,key就是bean中的ID,value就是生成的对象。
-
用户传入key,通过key来获取Map中的value(对象)
3.3 Bean的作用域
singleton(默认)、prototype、request、session、application
3.5 Bean的装配方式:
基于XML的装配;基于注解的装配; 基于Java的装配
Spring框架常用的注解 P34-35
① @Component(类注解)
该注解是一个泛化的概念,仅仅表示一个组件对象(Bean),可以作用在任何层次上。
② @Repository(DAO层)
该注解将数据访问层(DAO)的类标识为Bean,即注解数据访问层Bean,其功能与@Component相同
③ @Service(Service层)
该注解用于标注一个业务逻辑组件类(Service层),其功能与@Component相同
④ @Controller(Controller层)
该注解用于标识一个控制器组件类(Spring MVC的controller),其功能与@Component相同
⑤ @Autowired
该注解可以对类成员变量、方法及构造方法进行标注,完成自动装配的工作。通过使用@Autowired来消除setter和getter方法。默认按照Bean的类型进行装配
⑥ @Resource
该注解与@Autowired的功能一样,区别在于该注解默认是按照名称来装配注入的,只有当找不到与名称匹配的Bean才会按照类型来装配注入。
⑦ @Qualifier
该注解与@Autowired注解配合使用。当@Autowired注解需要按照名称来装配注入,则需要结合该注解一起使用,Bean的实例名称由@Qualifier注解的参数指定。
Spring注解中@Autowired和@Resource的区别
-
@Autowired默认按类型装配依赖对象,默认情况下要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,如果想按名称装配,可以结合@Qualifier注解一起使用。
-
@Resource注解有两个属性:name和type。name属性指定Bean实例名称,则按照名称来装配注入;type属性指定Bean类型,则按照Bean的类型进行装配。
第四章 Spring AOP
一、Spring AOP的基本概念,理解AOP的术语(P41)理解
(补充说明)切面(Aspect)是指封装横切到系统功能(如事务处理)的类。
连接点(Joint Point)和切入点(Point cut)是什么? 4
- 连接点是程序执行的一个点。例如,一个方法的执行或者一个异常的处理。在 Spring AOP 中,一个连接点总是代表一个方法执行。
- 切入点(Pointcut):匹配连接点的断言或者表达式。通知和一个切入点表达式关联,并在满足这个切入点表达式的连接点上运行。
二、动态代理:JDK动态代理(默认)、Cglib动态代理
比较JDK动态代理和Cglib动态代理
答:在AOP的源码中用到了两种动态代理来实现拦截切入功能:JDK动态代理和Cglib动态代理。两种方法同时存在,各有优劣。
-
JDK动态代理是由java内部的反射机制来实现,反射机制在生成类的过程中比较高效;而Cglib动态代理是通过继承来实现的,Cglib在生成类之后的相关执行过程中比较高效。
-
如果目标对象有接口则采用JDK动态代理,如果目标对象没有接口采用Cglib动态代理,Cglib动态代理是备用方案。
-
对接口创建代理优于对类创建代理,因为更加松耦合,所以Spring默认是使用JDK动态代理。
三、基于代理类的AOP实现
通知类型P48
(来自百度的解释)
前置通知 在一个方法执行之前,执行通知。
后置通知 在一个方法执行之后,不考虑其结果,执行通知。
返回后通知 在一个方法执行之后,只有在方法成功完成时,才能执行通知。
抛出异常后通知 在一个方法执行之后,只有在方法退出抛出异常时,才能执行通知。
环绕通知 在建议方法调用之前和之后,执行通知。
(课本内容)
org.aopalliance.intercept.MethodInterceptor(环绕通知): 在目标方法执行前后实施增强,可以应用于日志记录、事务管理等功能。
org.springframework.aop.MethodBeforeAdvice(前置通知): 在目标方法执行前实施增强,可以应用于权限管理等功能。
org.springframework.aop.AfterReturningAdvice(后置返回通知): 在目标方法执行成功后实施增强,可以应用于关闭流、上传文件、删除临时文件等功能。
org.springframework.aop.AfterAdvice(后置(最终)通知) 在目标方法执行后实施增强,与后置返回通知不同的是,不管是否发生异常都要执行该类通知,可应用于释放资源
org.springframework.aop.ThrowsAdvice (异常通知): 在方法抛出异常后实施增强,可以应用于处理异常、记录日志等功能
org.springframework.aop.IntroductionInterceptor(引介通知): 在目标类添加一些新的方法和属性,可以应用修目标类(增强类)。
AspectJ实现SpringAOP的两种方式:基于AspectJ的XML配置和基于注解开发AspectJ
基于XML配置开发AspectJ是指通过XML配置文件定义切面、切入点及通知,所有这些定义都必须在aop:config元素内。
切点表达式
切面表达式主要由:designators(指示器,匹配java方法),wildcards(通配符),operators(操作运算符)三部分组成
基于XML配置开发AspectJ的例子
1.导入AspectJ框架相关的JAR包
2.创建切面类
在src目录下,创建aspectj.xml包,在该包中创建切面类MyAspect,并在类中编写各种类型通知。
3.创建配置文件,并编写相关配置
在aspectj.xml包中,创建配置文件applicationContext.xml,并为aop:config元素及其子元素编写相关配置。
4.创建测试类
在aspectj.xml包中,创建测试类XMLAspectJTest,在主方法中使用Spring容器获取代理对象,并执行目标方法。
5.在dynamic.jdk.TestDaoImpl类中save方法中添加异常代码。
//例如
@Override
public void save() {
int n = 100/0;
System.out.println(“保存”);
}
基于注解开发AspectJ
1.创建切面类,并进行注解
在ch4应用的src目录下,创建aspectj.annotation包,在该包中创建切面类MyAspect。在该类中,首先使用@Aspect注解定义一个切面类,由于该类在Spring中是作为组件使用的,所以还需要使用@Component注解。然后,使用@Pointcut注解切入点表达式,并通过定义方法来表示切入点名称。最后在每个通知方法上添加相应的注解,并将切入点名称作为参数传递给需要执行增强的通知方法。
2.注解目标类
使用注解@Repository将目标类dynamic.jdk.TestDaoImpl注解为目标对象,注解代码如下:@Repository(“testDao”)
3.创建配置文件
在aspectj.annotation包中,创建配置文件applicationContext.xml,并在配置文件中指定需要扫描的包,使注解生效。同时,需要启动基于注解的AspectJ支持.
4.创建测试类
第5章 Spring的事务处理
5.1 Spring的数据库编程
- JDBC 连接数据库时需要配置数据库,配置数据源时需要的 4 个基本属性
MySQL数据库驱动、连接数据库的URL、连接数据库的用户名、连接数据库的密码
```javascript
<!-- 配置数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!-- MySQL数据库驱动 -->
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<!-- 连接数据库的URL -->
<property name="url" value="jdbc:mysql://localhost:3306/springtest?characterEncoding=utf8"/>
<!-- 连接数据库的用户名 -->
<property name="username" value="root"/>
<!-- 连接数据库的密码 -->
<property name="password" value="12345678"/>
</bean>
<!-- 配置JDBC模板 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
5.3 声明式事务处理
1. 在Spring配置文件中为JDBC配置事务时需要做哪四步工作,注意它们的正确顺序(XML 的方式)
1) 配置数据源
2) 配置事务管理器
3) 配置事务通知
4) 配置事务切面
2. Spring 的声明式事务管理可以通过两种方式来实现
一种是基于 XML 的方式,另一种是基于 @Transactional的注解方式
3. @Transactional 注解一般标注在 Service层上,主要是针对数据的增加、修改、删除进行事务管理。
第二部分 MyBatis
第6章 MyBatis开发入门
1. 在MyBatis核心配置文件中mybatis-config.xml必须配置SQL映射文件。
```javascript
<mappers>
<!-- 映射文件的位置 -->
<mapper resource="com/mybatis/mapper/UserMapper.xml"/>
</mappers>
- SQL映射文件的mapper配置标签中使用namespace来指定对应映射接口
例如UserMapper.xml中的配置:
第7章 映射器
-
SQL映射文件的常用配置元素P99
➣ cache :配置给定命名空间的缓存
➣ cache-ref :从其他命名空间引用缓存配置
➣ resultMap:提供映射规则(用来描述数据库结果集和对象的对应关系)
➣ sql:可以重用的 SQL 块,也可以被其他语句引用
➣ insert:映射插入语句
➣ update:映射更新语句
➣ delete:映射删除语句
➣ select:映射查询语句 -
SQL映射文件的常用配置元素的使用
在SQL映射文件中元素用于映射SQL的select语句,其示例代码如下:
<!-- 根据uid查询一个用户信息 -->
<select id="selectUserById" parameterType="Integer"
resultType="com.po.MyUser">
select * from user where uid = #{uid}
</select>
上述示例代码中,id的值是唯一标识符,它接收一个Integer类型的参数,返回一个MyUser类型的对象,结果集自动映射到MyUser属性。
元素用于映射插入语句,MyBatis执行完一条插入语句后,将返回一个整数表示其影响的行数。它的属性与元素的属性大部分相同,几个特有属性如下: keyProperty:该属性的作用是将插入或更新操作时的返回值赋值给PO类的某个属性,通常会设置为主键对应的属性。如果是联合主键,可以在多个值之间用逗号隔开。 keyColumn:该属性用于设置第几列是主键,当主键列不是表中的第一列时需要设置。如果是联合主键时,可以在多个值之间用逗号隔开。 useGeneratedKeys:该属性将使MyBatis使用JDBC的getGeneratedKeys()方法获取由数据库内部生产的主键,如MySQL、SQL Server等自动递增的字段,其默认值为false。
1.主键(自动递增)回填
MySQL、SQL Server等数据库的表格可以采用自动递增的字段作为主键。有时可能需要使用这个刚刚产生的主键,用以关联其他业务。
<!-- 添加一个用户,成功后将主键值回填给uid(po类的属性)-->
<insert id="addUser" parameterType="com.po.MyUser"
keyProperty="uid" useGeneratedKeys="true">
insert into user (uname,usex) values(#{uname},#{usex})
</insert>
2.自定义主键
如果实际工程中使用的数据库不支持主键自动递增(如Oracle),或者取消了主键自动递增的规则时,可以使用MyBatis的元素来自定义生成主键。
<insert id="insertUser" parameterType="com.po.MyUser">
<!-- 先使用selectKey元素定义主键,然后再定义SQL语句 -->
<selectKey keyProperty="uid" resultType="Integer" order="BEFORE">
select if(max(uid) is null, 1 , max(uid)+1) as newUid from user
</selectKey>
insert into user (uid,uname,usex) values(#{uid},#{uname},#{usex})
</insert>
和
和元素比较简单,它们的属性和元素、元素的属性差不多,执行后也返回一个整数,表示影响了数据库的记录行数。
<!-- 修改一个用户 -->
<update id="updateUser" parameterType="com.po.MyUser">
update user set uname = #{uname},usex = #{usex} where uid = #{uid}
</update>
<!-- 删除一个用户 -->
<delete id="deleteUser" parameterType="Integer">
delete from user where uid = #{uid}
</delete>
元素(提纲内无)
使用Map存储结果集
使用POJO存出结果集
<resultMap type="" id="">
<constructor><!-- 类在实例化时,用来注入结果到构造方法 -->
<idArg/><!-- ID参数,结果为ID -->
<arg/><!-- 注入到构造方法的一个普通结果 -->
</constructor>
<id/><!-- 用于表示哪个列是主键 -->
<result/><!-- 注入到字段或JavaBean属性的普通结果 -->
<association property=""/><!-- 用于一对一关联 -->
<collection property=""/><!-- 用于一对多、多对多关联 -->
<discriminator javaType=""><!-- 使用结果值来决定使用哪个结果映射 -->
<case value=""/> <!-- 基于某些值的结果映射 -->
</discriminator>
</resultMap>
元素表示结果映射集,是MyBatis中最重要也是最强大的元素。主要用来定义映射规则、级联的更新以及定义类型转化器等。
元素的type属性表示需要的POJO,id属性是resultMap的唯一标识。
子元素
-
SQL映射文件中的配置元素中的id属性必须唯一
-
Mybatis进行一对一和一对多关联查询时使用的标签分别是?
MyBatis如何处理一对一级联查询呢?
在MyBatis中,通过元素的子元素处理这种一对一级联关系。在元素中,通常使用以下属性。
property:指定映射到实体类的对象属性。
column:指定表中对应的字段(即查询返回的列名)。
javaType:指定映射到实体对象属性的类型。
select:指定引入嵌套查询的子SQL语句,该属性用于关联映射中的嵌套查询。
一对多关联查询可用三种方式实现:
可参考实例
文档:Mybatis一对多查询示例.note
链接:http://note.youdao.com/noteshare?id=4b17fafdaad543166f32f4c808c639e6
单步查询,利用collection标签为级联属性赋值;
分步查询:
利用association标签进行分步查询;
和使用collection标签的方式相同
利用collection标签进行分步查询:
指定collection标签的 property 属性;
通过select属性指定下一步查询使用的 statement id;
通过column属性向下一步查询传递参数
(以下为补充内容)
resultMap总结
resultType:
作用:
将查询结果按照sql列名pojo属性名一致性映射到pojo中。
场合:
常见一些明细记录的展示,比如用户购买商品明细,将关联查询信息全部展示在页面时,此时可直接使用resultType将每一条记录映射到pojo中,在前端页面遍历list(list中是pojo)即可。
resultMap:
使用association和collection完成一对一和一对多高级映射(对结果有特殊的映射要求)。
association:
作用:
将关联查询信息映射到一个pojo对象中。
场合:
为了方便查询关联信息可以使用association将关联订单信息映射为用户对象的pojo属性中,比如:查询订单及关联用户信息。
使用resultType无法将查询结果映射到pojo对象的pojo属性中,根据对结果集查询遍历的需要选择使用resultType还是resultMap。
collection:
作用:
将关联查询信息映射到一个list集合中。
场合:
为了方便查询遍历关联信息可以使用collection将关联信息映射到list集合中,比如:查询用户权限范围模块及模块下的菜单,可使用collection将模块映射到模块list中,将菜单列表映射到模块对象的菜单list属性中,这样的作的目的也是方便对查询结果集进行遍历查询。
如果使用resultType无法将查询结果映射到list集合中。
第8章 动态SQL
- 常用的动态SQL元素有哪些?理解它们的使用
if、choose (when, otherwise)、trim (where, set)、foreach
if
1.添加SQL映射语句
<!--在com.mybatis包的UserMapper.xml文件中,添加如下SQL映射语句:-->
<!-- 使用if元素,根据条件动态查询用户信息 -->
<select id="selectUserByIf" resultType="com.po.MyUser" parameterType="com.po.MyUser">
select * from user where 1=1
<if test="uname !=null and uname!=''">
and uname like concat('%',#{uname},'%')
</if>
<if test="usex !=null and usex!=''">
and usex = #{usex}
</if>
</select>
2.添加数据操作接口方法
//在com.dao包的UserDao接口中,添加如下数据操作接口方法:
public List selectUserByIf(MyUser user);
3.调用数据操作接口方法
//在com.controller包的UserController类中,添加如下程序,调用数据操作接口方法。
//使用if元素查询用户信息
MyUser ifmu = new MyUser();
ifmu.setUname("张");
ifmu.setUsex("女");
List<MyUser> listByif = userDao.selectUserByIf(ifmu);
System.out.println("if元素================");
for (MyUser myUser : listByif) {
System.out.println(myUser);
}
4.测试动态SQL语句
```javascript
//运行com.controller包中TestController主类,测试动态SQL语句。
select * from user where 1=1 and uname like concat('%',?,'%') and usex = ?
choose (when, otherwise)
//有些时候,不想用到所有的条件语句,而只想从中择其一二。
//针对这种情况,MyBatis 提供了choose元素,它有点像Java中的 switch 语句。
<!-- 使用choose、when、otherwise元素,根据条件动态查询用户信息 -->
<select id="selectUserByChoose" resultType="com.po.MyUser" parameterType="com.po.MyUser">
select * from user where 1=1
<choose>
<when test="uname !=null and uname!=''">
and uname like concat('%',#{uname},'%')
</when>
<when test="usex !=null and usex!=''">
and usex = #{usex}
</when>
<otherwise>
and uid > 10
</otherwise>
</choose>
</select>
//使用choose、when、otherwise元素,根据条件动态查询用户信息
MyUser chooseMu = new MyUser();
chooseMu.setUname("陈");
// chooseMu.setUsex("女");
List<MyUser> listChoose = userDao.selectUserByIf(chooseMu);
System.out.println("choose元素================");
for (MyUser myUser : listChoose) {
System.out.println(myUser);
}
trim (where, set)
元素的主要功能是可以在自己包含的内容前加上某些前缀,也可以在其后加上某些后缀,与之对应的属性是prefix和suffix;可以把包含内容的首部的某些内容覆盖,即忽略,也可以把尾部的某些内容覆盖,对应的属性是prefixOverrides和suffixOverrides;正因为元素有这样的功能,所以也可以非常简单地利用来代替元素的功能。
<!-- 使用trim元素,根据条件动态查询用户信息 -->
<!--UserMapper.xml-->
<select id="selectUserByTrim" resultType="com.po.MyUser" parameterType="com.po.MyUser">
select * from user
<trim prefix="where" prefixOverrides="and |or">
<if test="uname !=null and uname!=''">
and uname like concat('%',#{uname},'%')
</if>
<if test="usex !=null and usex!=''">
and usex = #{usex}
</if>
</trim>
</select>
//在com.dao包下的UserDao接口中添加数据操作方法
public List<MyUser> selectUserByTrim(MyUser user);
// 使用trim元素,根据条件动态查询用户信息
//UserController
MyUser trimMu = new MyUser();
trimMu.setUname("张");
trimMu.setUsex("女");
List<MyUser> listtrim = userDao.selectUserByTrim(trimMu);
System.out.println("trim元素================");
for (MyUser myUser : listtrim) {
System.out.println(myUser);
}
元素
元素的作用是会在写入元素的地方输出一个where语句,另外一个好处是不需要考虑元素里面的条件输出是什么样子的,MyBatis将智能处理。如果所有的条件都不满足,那么MyBatis就会查出所有的记录,如果输出后是and 开头的,MyBatis会把第一个and忽略,当然如果是or开头的,MyBatis也会把它忽略;此外,在元素中不需要考虑空格的问题,MyBatis将智能加上。
<!-- 使用where元素,根据条件动态查询用户信息 -->
<!--UserMapper.xml-->
<select id="selectUserByWhere" resultType="com.po.MyUser" parameterType="com.po.MyUser">
select * from user
<where>
<if test="uname !=null and uname!=''">
and uname like concat('%',#{uname},'%')
</if>
<if test="usex !=null and usex!=''">
and usex = #{usex}
</if>
</where>
</select>
//在com.dao包下的UserDao接口中添加数据操作方法
public List<MyUser> selectUserByWhere(MyUser user);
// 使用where元素,根据条件动态查询用户信息
//UserController
MyUser whereMu = new MyUser();
whereMu.setUname("张");
whereMu.setUsex("女");
List<MyUser> listWhere = userDao.selectUserByWhere(whereMu);
System.out.println("where元素================");
for (MyUser myUser : listWhere) {
System.out.println(myUser);
}
元素
在动态update语句中,可以使用元素动态更新列。
<!-- 使用set元素,动态修改一个用户 -->
<!--UserMapper.xml-->
<update id="updateUserBySet" parameterType="com.po.MyUser">
update user
<set>
<if test="uname != null">uname=#{uname},</if>
<if test="usex != null">usex=#{usex}</if>
</set>
where uid = #{uid}
</update>
//UserDao
//使用set元素,动态修改一个用户
public int updateUserBySet(MyUser user);
//使用set元素,动态修改一个用户
//UserController
System.out.println("set元素================");
MyUser setMu = new MyUser();
setMu.setUid(31);
setMu.setUname("张久");
int setup=userDao.updateUserBySet(setMu);
System.out.println("set元素修改了"+setup+"条记录");
System.out.println("================");
foreach
元素主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合。foreach元素的属性主要有item,index,collection,open,separator,close。item表示集合中每一个元素进行迭代时的别名,index指定一个名字,用于表示在迭代过程中,每次迭代到的位置,open表示该语句以什么开始,separator表示在每次进行迭代之间以什么符号作为分隔符,close表示以什么结束。在使用时,最关键的也是最容易出错的是collection属性,该属性是必选的,但在不同情况下,该属性的值是不一样的,主要有以下3种情况:
如果传入的是单参数且参数类型是一个List的时候,collection属性值为list。
如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array。
如果传入的参数是多个时,需要把它们封装成一个Map,当然单参数也可以封装成Map。Map的key是参数名,collection属性值是传入的List或array对象在自己封装的Map中的key。
<!--UserMapper.xml-->
<!-- 使用foreach元素,查询用户信息 -->
<select id="selectUserByForeach" resultType="com.po.MyUser" parameterType="List">
select * from user where uid in
<foreach item="item" index="index" collection="list" open="(" separator="," close=")">
#{item}
</foreach>
</select>
//UserDao接口
public List<MyUser> selectUserByForeach(List<Integer>listId);
// 使用foreach元素,根据条件动态查询用户信息
//UserController
List<Integer> listIds = new ArrayList<Integer>();
listIds.add(31);
listIds.add(32);
List<MyUser> listForeach = userDao.selectUserByForeach(listIds);
System.out.println("Foreach元素================");
for (MyUser myUser : listForeach) {
System.out.println(myUser);
}
- 给出动态SQL语句,根据输入写出正确的SQL语句
**3. MyBatis 中#{}与KaTeX parse error: Expected 'EOF', got '#' at position 18: …绑定参数有什么区别?** ① #̲{ }将传入的数据都当成一个字…{ }将传入的数据直接显示生成在sql中。如:order by KaTeX parse error: Expected 'EOF', got '#' at position 77: …order by id。 ③ #̲{ }方式能够很大程度防止sq…{}方式无法防止Sql注入。
④ KaTeX parse error: Expected 'EOF', got '#' at position 32: …,例如传入表名。 ⑤ 一般能用#̲{}的就别用{}。
第9章 Spring MVC入门
1. SpringMVC 的工作流程P133
工作流程如下:
-
客户端请求提交到DispatcherServlet;
-
由DispatcherServlet控制器寻找一个或多个HandlerMapping,找到处理请求的Controller;
-
DispatcherServlet将请求提交到Controller,Controller调用业务逻辑处理后返回ModelAndView;
-
DispatcherServlet寻找一个或多个ViewResolver视图解析器,找到ModelAndView指定的视图;
-
视图负责将结果显示到客户端。
-
在开发Spring MVC应用时,需要在web.xml中部署配置前端控制器DispatcherServlet
第10章 Spring MVC的Controller
10.1控制器注解
@Controller
@Controller注解表明了某类是作为控制器的角色而存在的。
(使用org.springframework.stereotype.Controller注解类型声明某类的实例是一个控制器。)。
在SpringMVC中使用扫描机制找到应用中所有基于注解的控制器类,为了让控制器类被Spring MVC框架扫描到,需要在配置文件中声明spring-context,并使用context:component-scan/元素指定控制器类的基本包(请确保所有控制器类都在基本包及其子包下)。
示例代码:
package controller;
import org.springframework.stereotype.Controller;
/** “@Controller”表示IndexController的实例是一个控制器
* @Controller相当于@Controller("indexController")
* 或@Controller(value = "indexController")
*/
@Controller
public class IndexController {
//处理请求的方法
}
@RequestMapping
@RequestMapping 将请求的url与处理方法一一对应起来
1.方法级别注解
@Controller
public class IndexController {
@RequestMapping(value = "/index/login")
public String login() {
/**login代表逻辑视图名称,需要根据Spring MVC配置
* 文件中internalResourceViewResolver的前缀和后缀找到对应的物理视图 */
return "login";
}
@RequestMapping(value = "/index/register")
public String register() {
return "register";
}
}
2.类级别注解
@Controller
@RequestMapping("/index")
public class IndexController {
@RequestMapping("/login")
public String login() {
return "login";
}
@RequestMapping("/register")
public String register() {
return "register";
}
}
10.2 Controller接收请求参数的常用方式(6种方式)
通过实体bean接收请求参数
通过处理方法的形参接收请求参数
通过HttpServletRequest接收请求参数
通过@PathVariable接收URL中的请求参数
通过@RequestParam接收请求参数
通过@ModelAttribute接收请求参数
10.3 重定向和转发
1.转发到一个请求方法(同一个控制器类里,可省略/index/)
return "forward: /index/login";
2.重定向到一个请求方法
return "redirect:/index/isRegister";
3.转发到一个视图
return "register"; //加上前缀和后缀 /WEB-INF/jsp/register.jsp
第12章 数据绑定和表单标签库
认识 JSON的两种数据结构(对象结构、数组结构)
JSON(JavaScript Object Notation,JS对象标记)是一种轻量级的数据交换格式。
与XML一样,JSON也是基于纯文本的数据格式。它有两种数据结构。
1.对象结构
对象结构以“{”开始,以“}”结束。中间部分由0个或多个以英文“,”分隔的key/value对构成,key和value之间以英文“:”分隔。对象结构的语法结构如下:
{
key1:value1,
key2:value2,
…
}
其中,key必须为String类型,value可以是String、Number、Object、Array等数据类型。
2.数组结构
数组结构以“[”开始,以“]”结束。中间部分由0个或多个以英文“,”分隔的值的列表组成。数组结构的语法结构如下:
[
value1,
value2,
…
]
第13章 拦截器
1. 拦截器的定义,实现HandlerInterceptor接口,实现接口的哪三个方法。分别在什么时候执行?
-
preHandle()方法:该方法在控制器的处理请求方法之前执行,其返回值表示是否中断后续操作。返回true表示继续向下执行,返回false表示中断后续操作。
-
postHandle()方法:该方法在控制器的处理请求方法调用之后,解析视图之前执行。可以通过此方法对请求域中的模型和视图做进一步的修改。
-
afterCompletion()方法:该方法在控制器的处理请求方法执行完成后执行,即视图渲染结束后执行。可以通过此方法实现一些资源清理、记录日志信息等工作。
2. 拦截器的配置,path的值
- /**的意思是所有文件夹及里面的子文件夹
- /*是所有文件夹,不含子文件夹
- /是web项目的根目录
第17章 文件的上传和下载
- 文件上传,表单的enctype属性值必须设置为multipart/form-data
- 文件上传是通过 MultipartResolver 对象实现的,
defaultEncoding="UTF-8"
maxUploadSize="5400000"
uploadTempDir="fileUpload/temp"
defaultEncoding="UTF-8" //是请求的编码格式,默认为iso-8859-1
maxUploadSize="5400000"//是允许上传文件的最大值,单位为字节
uploadTempDir="fileUpload/temp" //为上传文件的临时路径
第19章 SSM框架整合
分别 写出各个配置文件的配置步骤
-
web.xml
-
applicationContext.xml
-
springmvc-servlet.xml
-
mybatis-config.xml
- 写出SSM框架整合,配置文件web.xml的基本配置步骤
① 实例化applicationContext容器
② 配置前端控制器
③ 定义过滤器解决post提交乱码问题
2. 写出SSM框架整合,配置文件 applicationContext.xml的基本配置步骤。
答:
- 开启包扫描 Service
- 配置数据源(driverClassName、url、username、password)
- 配置事务管理器
- 基于XML声明式事务处理(配置事务通知、配置事务切面);
基于注解的声明式事务处理(开启事务注解) - 配置MyBatis工厂(属性dataSource:加载数据源,属性configLocation:指定mybatis核心配置文件的路径)
- 配置Mapper代理开发,使用Spring自动扫描MyBatis的接口并装配,Spring将指定包中所有被@Mapper注解的接口自动装配为MyBatis的映射接口。
-
写出SSM框架整合, 配置文件springmvc-servlet.xml的基本配置步骤。
① 开启包扫描,扫描控制器类
② 开启mvc注解,允许静态资源可见
③ 配置视图解析器(prefix:配置前缀,suffix:配置后缀) -
MyBatis核心配置文件的配置
<mapper resource="com/mybatis/UserMapper.xml"/>
<mapper resource="com/mybatis/ProdMapper.xml"/>
参考试题 Spring试题
https://wenku.baidu.com/view/0c81274586c24028915f804d2b160b4e767f81d5.html
附录:各个配置文件的代码样例
Spring-MVC-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
此处省略加载xsd文件之类的,与applicationContext.xml文件类似">
<!-- 使用扫描机制,扫描包 -->
<context:component-scan base-package="com.controller" />
<mvc:annotation-driven />
<!-- 静态资源需要单独处理,不需要dispatcher servlet -->
<mvc:resources location="/css/" mapping="/css/**"></mvc:resources>
<mvc:resources location="/images/" mapping="/images/**"></mvc:resources>
<!-- 查看图片时,logos文件夹不需要dispatcher servlet -->
<mvc:resources location="/logos/" mapping="/logos/**"></mvc:resources>
<!-- 配置视图解析器 -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- 后缀 -->
<property name="suffix" value=".jsp" />
</bean>
<!-- 配置MultipartResolver 用于文件上传 使用spring的CommosMultipartResolver -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"
p:defaultEncoding="UTF-8"
p:maxUploadSize="5400000"
p:uploadTempDir="fileUpload/temp"
>
</bean>
<!-- defaultEncoding="UTF-8" 是请求的编码格式,默认为iso-8859-1
maxUploadSize="5400000" 是允许上传文件的最大值,单位为字节
uploadTempDir="fileUpload/temp" 为上传文件的临时路径-->
<!-- 托管MyExceptionHandler -->
<bean class="com.exception.MyExceptionHandler"/>
</beans>
applicationContext.xml
<?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: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/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 配置数据源 -->
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/shop?characterEncoding=utf8" />
<property name="username" value="root" />
<property name="password" value="123456" />
<!-- 最大连接数 -->
<property name="maxTotal" value="30"/>
<!-- 最大空闲连接数 -->
<property name="maxIdle" value="10"/>
<!-- 初始化连接数 -->
<property name="initialSize" value="5"/>
</bean>
<!-- 添加事务支持 -->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 开启事务注解-->
<tx:annotation-driven transaction-manager="txManager" />
<!-- 配置MyBatis工厂,同时指定数据源,并与MyBatis完美整合 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- configLocation的属性值为MyBatis的核心配置文件 -->
<property name="configLocation" value="classpath:com/mybatis/mybatis-config.xml"/>
</bean>
<!--Mapper代理开发,使用Spring自动扫描MyBatis的接口并装配
(Spring将指定包中所有被@Mapper注解标注的接口自动装配为MyBatis的映射接口) -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- mybatis-spring组件的扫描器 ,必须写全dao的包名,且只能扫描一个dao包-->
<property name="basePackage" value="com.dao"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
<!-- 指定需要扫描的包(包括子包),使注解生效。dao包在mybatis-spring组件中已经扫描,这里不再需要扫描-->
<context:component-scan base-package="com.service"/>
</beans>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
id="WebApp_ID" version="3.1">
<!-- 实例化ApplicationContext容器 -->
<context-param>
<!-- 加载src目录下的applicationContext.xml文件 -->
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:applicationContext.xml
</param-value>
</context-param>
<!-- 指定以ContextLoaderListener方式启动Spring容器 -->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!--配置DispatcherServlet -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</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>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<typeAlias alias="Auser" type="com.po.Auser"/>
<typeAlias alias="Goods" type="com.po.Goods"/>
<typeAlias alias="GoodsType" type="com.po.GoodsType"/>
<typeAlias alias="Notice" type="com.po.Notice"/>
<typeAlias alias="Buser" type="com.po.Buser"/>
<typeAlias alias="Order" type="com.po.Order"/>
</typeAliases>
<mappers>
<mapper resource="com/mybatis/admin/UserMapper.xml"/>
<mapper resource="com/mybatis/admin/AdminMapper.xml"/>
<mapper resource="com/mybatis/admin/AdminTypeMapper.xml"/>
<!--省略其余mapper.xml-->
</mappers>
</configuration>
以UserMapper.xml为例
<?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="com.dao.UserDao">
<select id="login" resultType="Buser" parameterType="Buser">
select * from busertable where bemail = #{bemail} and bpwd = #{bpwd}
</select>
<insert id="register" parameterType="Buser">
insert into busertable (id, bemail, bpwd) values (null, #{bemail}, #{bpwd})
</insert>
</mapper>
以User为例,Spring容器下各文件样例
com.pojo.User
package com.pojo;
public class User {
private Integer id;
private String bemail;
private String bpwd;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getBemail() {
return bemail;
}
public void setBemail(String bemail) {
this.bemail = bemail;
}
public String getBpwd() {
return bpwd;
}
public void setBpwd(String bpwd) {
this.bpwd = bpwd;
}
}
com.dao.UserDao(数据访问层)
package com.dao;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import com.pojo.User;
@Repository("userDao")
@Mapper
public interface UserDao {
public int register(User user);
public List<User> login(User user);
}
com.service.UserService(业务逻辑层)
package com.service;
import javax.servlet.http.HttpSession;
import org.springframework.ui.Model;
import com.po.Buser;
public interface UserService {
public String register(Buser buser,Model model, HttpSession session, String code);
public String login(Buser buser,Model model, HttpSession session, String code);
}
com.service.UserServiceImpl
package com.service;
import java.util.List;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import com.dao.UserDao;
import com.pojo.User;
@Service("userService")
@Transactional
public class UserServiceImpl implements UserService{
@Autowired
private UserDao userDao;
@Override
public String register(User buser, Model model, HttpSession session, String code) {
if(!code.equalsIgnoreCase(session.getAttribute("code").toString())) {
model.addAttribute("codeError", "验证码错误!");
return "before/register";
}
int n = userDao.register(buser);
if(n > 0) {
return "before/login";
}else {
model.addAttribute("msg", "注册失败!");
return "before/register";
}
}
@Override
public String login(User buser, Model model, HttpSession session, String code) {
if(!code.equalsIgnoreCase(session.getAttribute("code").toString())) {
model.addAttribute("msg", "验证码错误!");
return "before/login";
}
Buser ruser = null;
List<Buser> list = userDao.login(buser);
if(list.size() > 0) {
ruser = list.get(0);
}
if(ruser != null) {
session.setAttribute("bruser", ruser);
return "forward:/before";
}else {
model.addAttribute("msg", "用户名或密码错误!");
return "before/login";
}
}
}
com.controller.UserController(控制层)
package com.controller;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import com.pojo.User;
import com.service.UserService;
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/register")
public String register(@ModelAttribute User buser,Model model, HttpSession session, String code) {
return userService.register(buser, model, session, code);
}
@RequestMapping("/login")
public String login(@ModelAttribute Buser buser,Model model, HttpSession session, String code) {
return userService.login(buser, model, session, code);
}
@RequestMapping("/exit")
public String exit(HttpSession session) {
session.invalidate();
return "forward:/before";
}
}