SSM 73问 mybaits 21问 Mybaits与Hibernate的异同? Hibernate与MyBatis都是ORM框架,都有相应的代码生成工具,可以生成简单基本的DAO层方法。
Mybaits是半ORM框架,Hibernate是全ORM框架
Mybaits需要手动写SQL语句,Hibernate不需要
什么是ORM? 对象关系映射 (英语:Object Relational Mapping ,简称ORM ,或O/RM ,或O/R mapping ),是一种程序设计技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。
目的是使用面向对象的方法操纵数据库
mybatis怎么配置环境信息? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <environments default ="development" > <environment id ="development" > <transactionManager type ="JDBC" > <property name ="..." value ="..." /> </transactionManager > <dataSource type ="POOLED" > <property name ="driver" value ="${driver}" /> <property name ="url" value ="${url}" /> <property name ="username" value ="${username}" /> <property name ="password" value ="${password}" /> </dataSource > </environment > </environments >
mybaits的setting有什么作用? 这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。下表描述了设置中各项的意图、默认值等。
设置参数 描述 有效值 默认值 cacheEnabled 该配置影响的所有映射器中配置的缓存的全局开关。 true,false true lazyLoadingEnabled 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置fetchType
属性来覆盖该项的开关状态。 true,false false aggressiveLazyLoading 当启用时,对任意延迟属性的调用会使带有延迟加载属性的对象完整加载;反之,每种属性将会按需加载。 true,false false (在 3.4.1 及之前的版本中默认为 true) multipleResultSetsEnabled 是否允许单一语句返回多结果集(需要兼容驱动)。 true,false true useColumnLabel 使用列标签代替列名。不同的驱动在这方面会有不同的表现, 具体可参考相关驱动文档或通过测试这两种不同的模式来观察所用驱动的结果。 true,false true useGeneratedKeys 允许 JDBC 支持自动生成主键,需要驱动兼容。 如果设置为 true 则这个设置强制使用自动生成主键,尽管一些驱动不能兼容但仍可正常工作(比如 Derby)。 true,false False autoMappingBehavior 指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示取消自动映射;PARTIAL 只会自动映射没有定义嵌套结果集映射的结果集。 FULL 会自动映射任意复杂的结果集(无论是否嵌套)。 NONE, PARTIAL, FULL PARTIAL defaultExecutorType 配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(prepared statements); BATCH 执行器将重用语句并执行批量更新。 SIMPLE REUSE BATCH SIMPLE defaultStatementTimeout 设置超时时间,它决定驱动等待数据库响应的秒数。 Any positive integer Not Set (null) safeRowBoundsEnabled 允许在嵌套语句中使用分页(RowBounds)。 true,false False mapUnderscoreToCamelCase 是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。 true, false False localCacheScope MyBatis 利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速重复嵌套查询。 默认值为 SESSION,这种情况下会缓存一个会话中执行的所有查询。 若设置值为 STATEMENT,本地会话仅用在语句执行上,对相同 SqlSession 的不同调用将不会共享数据。 SESSION,STATEMENT SESSION jdbcTypeForNull 当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。 某些驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。 JdbcType enumeration. Most common are: NULL, VARCHAR and OTHER OTHER lazyLoadTriggerMethods 指定哪个对象的方法触发一次延迟加载。 A method name list separated by commas equals,clone,hashCode,toString defaultScriptingLanguage 指定动态 SQL 生成的默认语言。 A type alias or fully qualified class name. org. apache .ibatis. scripting. xmltags. XMLDynamicLanguageDriver callSettersOnNulls 指定当结果集中值为 null 的时候是否调用映射对象的 setter(map 对象时为 put)方法,这对于有 Map.keySet() 依赖或 null 值初始化的时候是有用的。注意基本类型(int、boolean等)是不能设置成 null 的。 true,false false logPrefix 指定 MyBatis 增加到日志名称的前缀。 Any String Not set logImpl 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 SLF4J ,LOG4J ,LOG4J2, JDK_LOGGING, COMMONS_LOGGING, STDOUT_LOGGING, NO_LOGGING Not set proxyFactory 指定 Mybatis 创建具有延迟加载能力的对象所用到的代理工具。 CGLIB JAVASSIST CGLIB vfslmpl 指定 VFS 的实现 自定义 VFS 的实现的类全限定名,以逗号分隔。 no set useActualParamName 允许使用方法签名中的名称作为语句参数名称。 为了使用该特性,你的项目必须采用 Java 8 编译,并且加上 -parameters
选项。(新增于 3.4.1) true \ false configurationFactory 指定一个提供 Configuration
实例的类。 这个被返回的 Configuration 实例用来加载被反序列化对象的延迟加载属性值。 这个类必须包含一个签名为static Configuration getConfiguration()
的方法。(新增于 3.2.3) 类型别名或者全类名. no set
一个配置完整的 settings 元素的示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <settings > <setting name ="cacheEnabled" value ="true" /> <setting name ="lazyLoadingEnabled" value ="true" /> <setting name ="multipleResultSetsEnabled" value ="true" /> <setting name ="useColumnLabel" value ="true" /> <setting name ="useGeneratedKeys" value ="false" /> <setting name ="autoMappingBehavior" value ="PARTIAL" /> <setting name ="defaultExecutorType" value ="SIMPLE" /> <setting name ="defaultStatementTimeout" value ="25" /> <setting name ="safeRowBoundsEnabled" value ="false" /> <setting name ="mapUnderscoreToCamelCase" value ="false" /> <setting name ="localCacheScope" value ="SESSION" /> <setting name ="jdbcTypeForNull" value ="OTHER" /> <setting name ="lazyLoadTriggerMethods" value ="equals,clone,hashCode,toString" /> </settings >
如何配置类型别名? 类型别名是为 Java 类型设置一个短的名字,存在的意义仅在于用来减少类完全限定名的冗余。例如:
1 2 3 4 5 6 7 8 <typeAliases > <typeAlias alias ="Author" type ="domain.blog.Author" /> <typeAlias alias ="Blog" type ="domain.blog.Blog" /> <typeAlias alias ="Comment" type ="domain.blog.Comment" /> <typeAlias alias ="Post" type ="domain.blog.Post" /> <typeAlias alias ="Section" type ="domain.blog.Section" /> <typeAlias alias ="Tag" type ="domain.blog.Tag" /> </typeAliases >
当这样配置时,Blog
可以用在任何使用domain.blog.Blog
的地方。
也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:
1 2 3 <typeAliases > <package name ="domain.blog" /> </typeAliases >
每一个在包 domain.blog
中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author
的别名为 author
;若有注解,则别名为其注解值。看下面的例子:
1 2 3 4 @Alias("author") public class Author { ... }
三种数据源类型的区别? UNPOOLED – 这个数据源的实现只是每次被请求时打开和关闭连接。虽然一点慢,它对在及时可用连接方面没有性能要求的简单应用程序是一个很好的选择。
POOLED – 这种数据源的实现利用”池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。 这是一种使得并发 Web 应用快速响应请求的流行处理方式。
JNDI – 这个数据源的实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用。
如何指定映射文件? 最佳的方式是告诉 MyBatis 到哪里去找映射文件。你可以使用相对于类路径的资源引用, 或完全限定资源定位符(包括 file:///
的 URL),或类名和包名等。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <mappers > <mapper resource ="org/mybatis/builder/AuthorMapper.xml" /> </mappers > <mappers > <mapper url ="file:///var/mappers/AuthorMapper.xml" /> </mappers > <mappers > <mapper class ="org.mybatis.builder.AuthorMapper" /> </mappers > <mappers > <package name ="org.mybatis.builder" /> </mappers >
select与属性的用法? 简单查询的 select 元素是非常简单的。比如:
1 2 3 4 5 6 7 8 <select id ="selectPerson" parameterType ="int" resultType ="hashmap" > SELECT * FROM PERSON WHERE ID = #{id}</select >
select 元素有很多属性允许你配置,来决定每条语句的作用细节。
1 2 3 4 5 6 7 8 9 10 11 12 <select id ="selectPerson" parameterType ="int" parameterMap ="deprecated" resultType ="hashmap" resultMap ="personResultMap" flushCache ="false" useCache ="true" timeout ="10000" fetchSize ="256" statementType ="PREPARED" resultSetType ="FORWARD_ONLY" >
属性的含义:
属性 描述 id 在命名空间中唯一的标识符,可以被用来引用这条语句。 parameterType 将会传入这条语句的参数类的完全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过 TypeHandler 推断出具体传入语句的参数,默认值为 unset。 resultType 从这条语句中返回的期望类型的类的完全限定名或别名。注意如果是集合情形,那应该是集合可以包含的类型,而不能是集合本身。使用 resultType 或 resultMap,但不能同时使用。 resultMap 外部 resultMap 的命名引用。结果集的映射是 MyBatis 最强大的特性,对其有一个很好的理解的话,许多复杂映射的情形都能迎刃而解。使用 resultMap 或 resultType,但不能同时使用。 flushCache 将其设置为 true,任何时候只要语句被调用,都会导致本地缓存和二级缓存都会被清空,默认值:false。 useCache 将其设置为 true,将会导致本条语句的结果被二级缓存,默认值:对 select 元素为 true。 timeout 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为 unset(依赖驱动)。 fetchSize 这是尝试影响驱动程序每次批量返回的结果行数和这个设置值相等。默认值为 unset(依赖驱动)。 statementType STATEMENT,PREPARED 或 CALLABLE 的一个。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。 resultSetType FORWARD_ONLY,SCROLL_SENSITIVE 或 SCROLL_INSENSITIVE 中的一个,默认值为 unset (依赖驱动)。 databaseId 如果配置了 databaseIdProvider,MyBatis 会加载所有的不带 databaseId 或匹配当前 databaseId 的语句;如果带或者不带的语句都有,则不带的会被忽略。 resultOrdered 这个设置仅针对嵌套结果 select 语句适用:如果为 true,就是假设包含了嵌套结果集或是分组了,这样的话当返回一个主结果行的时候,就不会发生有对前面结果集的引用的情况。这就使得在获取嵌套的结果集的时候不至于导致内存不够用。默认值:false。 resultSets 这个设置仅对多结果集的情况适用,它将列出语句执行后返回的结果集并每个结果集给一个名称,名称是逗号分隔的。
insert、update、delete的用法? 数据变更语句 insert,update 和 delete 的实现非常接近:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <insert id ="insertAuthor" parameterType ="domain.blog.Author" flushCache ="true" statementType ="PREPARED" keyProperty ="" keyColumn ="" useGeneratedKeys ="" timeout ="20" > <update id ="updateAuthor" parameterType ="domain.blog.Author" flushCache ="true" statementType ="PREPARED" timeout ="20" > <delete id ="deleteAuthor" parameterType ="domain.blog.Author" flushCache ="true" statementType ="PREPARED" timeout ="20" >
Insert, Update 和 Delete 的属性
属性 描述 id 命名空间中的唯一标识符,可被用来代表这条语句。 parameterType 将要传入语句的参数的完全限定类名或别名。这个属性是可选的,因为 MyBatis 可以通过 TypeHandler 推断出具体传入语句的参数,默认值为 unset。 flushCache 将其设置为 true,任何时候只要语句被调用,都会导致本地缓存和二级缓存都会被清空,默认值:true(对应插入、更新和删除语句)。 timeout 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为 unset(依赖驱动)。 statementType STATEMENT,PREPARED 或 CALLABLE 的一个。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。 useGeneratedKeys (仅对 insert 和 update 有用)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系数据库管理系统的自动递增字段),默认值:false。 keyProperty (仅对 insert 和 update 有用)唯一标记一个属性,MyBatis 会通过 getGeneratedKeys 的返回值或者通过 insert 语句的 selectKey 子元素设置它的键值,默认:unset。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。 keyColumn (仅对 insert 和 update 有用)通过生成的键值设置表中的列名,这个设置仅在某些数据库(像 PostgreSQL)是必须的,当主键列不是表中的第一列的时候需要设置。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。 databaseId 如果配置了 databaseIdProvider,MyBatis 会加载所有的不带 databaseId 或匹配当前 databaseId 的语句;如果带或者不带的语句都有,则不带的会被忽略。
下面就是 insert,update 和 delete 语句的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <insert id ="insertAuthor" > insert into Author (id,username,password,email,bio) values (#{id},#{username},#{password},#{email},#{bio})</insert > <update id ="updateAuthor" > update Author set username = #{username}, password = #{password}, email = #{email}, bio = #{bio} where id = #{id}</update > <delete id ="deleteAuthor" > delete from Author where id = #{id}</delete >
两种字符串替换的区别? #{} ${} 参数占位符,即预编译 字符串替换符,即SQL拼接 很大程度上能防止sql 注入 不能防止sql 注入 将传入的数据都当成一个字符串,会对传入的变量自动加一个单引号 将传入的参数直接显示生成在sql中,且不加任何引号 排序时使用order by 动态参数时需要注意,用$而不是#
三种自动映射等级? 1 <setting name ="autoMappingBehavior" value ="PARTIAL" />
NONE 表示取消自动映射
PARTIAL 只会自动映射没有定义嵌套结果集映射的结果集
FULL 会自动映射任意复杂的结果集(无论是否嵌套)
if标签的作用? 1 2 3 4 5 6 7 8 9 <select id ="findActiveBlogWithTitleLike" resultType ="Blog" > SELECT * FROM BLOG WHERE state = ‘ACTIVE’ <if test ="title != null" > AND title like #{title} </if > </select >
foreach标签的用法? 1 2 3 4 5 6 7 8 9 10 11 <select id ="selectPostIn" resultType ="domain.blog.Post" > SELECT * FROM POST P WHERE ID in <foreach item ="item" index ="index" collection ="list" open ="(" separator ="," close =")" > #{item} </foreach > </select >
怎么配置日志级别? 1 2 3 4 log4j.rootLogger =ERROR, stdout log4j.logger.org.mybatis.example.BlogMapper =TRACE
一级缓存和二级缓存的定义与区别? 一级缓存定义一级缓存作用域是sqlsession级别的,同一个sqlsession中执行相同的sql查询(相同的sql和参数),第一次会去查询数据库并写到缓存中,第二次从一级缓存中取。 一级缓存是基于 PerpetualCache 的 HashMap 本地缓存,默认打开一级缓存。 清空一级缓存如果中间sqlSession去执行commit操作(执行插入、更新、删除),则会清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。 一级缓存时执行commit,close,增删改等操作,就会清空当前的一级缓存;当对SqlSession执行更新操作(update、delete、insert)后并执行commit时,不仅清空其自身的一级缓存(执行更新操作的效果),也清空二级缓存(执行commit()的效果)。 一级缓存无过期时间,只有生命周期 二级缓存简介它指的是Mybatis中SqlSessionFactory对象的缓存。由同一个SqlSessionFactory对象创建的SqlSession共享其缓存。 二级缓存是 mapper 映射级别的缓存,多个 SqlSession 去操作同一个 Mapper 映射的 sql 语句,多个SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的。 、 何时存入在关闭sqlsession后(close),才会把该sqlsession一级缓存中的数据添加到namespace的二级缓存中。 开启了二级缓存后,还需要将要缓存的pojo实现Serializable接口,为了将缓存数据取出执行反序列化操作,因为二级缓存数据存储介质多种多样,不一定只存在内存中,有可能存在硬盘中。 二级缓存有过期时间,但没有后台线程进行检测需要注意的是,并不是key-value的过期时间,而是这个cache的过期时间,是flushInterval,意味着整个清空缓存cache,所以不需要后台线程去定时检测。 每当存取数据的时候,都要检测一下cache的生命时间,默认是1小时,如果这个cache存活了一个小时,那么将整个清空一下。 当 Mybatis 调用 Dao 层查询数据库时,先查询二级缓存,二级缓存中无对应数据,再去查询一级缓存,一级缓存中也没有,最后去数据库查找。 useCache与flushCache的作用? 1 2 3 4 5 6 <select flushCache ="false" useCache ="true" >
Redis的概念? Redis 是一个高性能的key-value数据库。经常用作缓存
那个注解是对dao组件的修饰? JavaModelGenerator配置、sqlMapperGenerator配置与JavaClientGenerator配置的作用? JavaModelGenerator配置生成的实体类的存放的位置(entity层的java文件) sqlMapperGenerator配置生成的映射文件的位置(resources/dao中的xml文件) JavaClientGenerator配置生成的mapper接口文件的位置(dao层中的java文件) 如何实现分页? 导入依赖包
1 2 3 4 5 <dependency > <groupId > com.github.pagehelper</groupId > <artifactId > pagehelper-spring-boot-starter</artifactId > <version > 1.2.3</version > </dependency >
配置properties
1 2 3 4 5 pagehelper.helper-dialect =mysql pagehelper.reasonable =true pagehelper.support-methods-arguments =true pagehelper.params =count=countSql
使用
1 2 3 4 5 6 7 8 9 10 11 @Transactional(readOnly = true) @Override public PageInfo<Student> getStudentListByBatchName (String batchName, Integer pageNo) { PageHelper.startPage(pageNo, 5 ); List<Student> list = studentMapper.getListByBatchName(batchName); PageInfo<Student> pageInfo=new PageInfo <>(list,5 ); return pageInfo; }
分页最后封装成什么数据? PageInfo<T>
spring Framework 40问 依赖注入的概念? Spring 通过 IoC 容器来管理所有 Java 对象的实例化和初始化,控制对象与对象之间的依赖关系.
控制反转核心思想就是由 Spring 负责对象的创建。DI是IOC的一种。在对象创建过程中,Spring 会自动根据依赖关系,将它依赖的对象注入到当前对象中,这就是所谓的“依赖注入”。
springCoreContainer是什么?
Core:核心工具包,包括字节码操作cglib、asm,资源的抽象Resource,对象实例化化工具等等。 Beans:Bean 的定义、Bean 的创建以及对 Bean 的解析。 Context:Context模块建立在Core和Beans模块之上,是Bean运行环境(即保存维护Bean的状态、数据,Bean之间的关系),又称之为Ioc容器。 SpEL:提供了一个强大的表达式语言,可以在运行时查询和操作对象。 springIoC容器的类型? spring BeanFactory 容器 是Spring bean容器的根接口,提供获取bean,是否包含bean,是否单例与原型,获取bean类型,bean 别名的方法 。 BeanFactory不支持国际化功能 不支持事件机制 没有扩展ResourceLoader,只能加载一个Resource BeanFactory采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化 BeanFactory需要手动注册 Spring ApplicationContext 容器 ApplicationContext继承了BeanFactory 扩展了MessageResource接口,因而具有消息处理的能力(i18N) 通过ApplicationEvent和ApplicationListener这两个接口实现事件机制 扩展了ResourceLoader(资源加载器)接口,从而可以用来加载多个Resource 在容器启动时,一次性创建了所有的Bean 而ApplicationContext则是自动注册 ApplicationContext容器的实现有哪些? ApplicationContext 有两个直接子接口:WebApplicationContext 和 ConfigurableApplicationContext。
ConfigurableApplicationContext:扩展于ApplicationContext, 新增加两个主要方法。refresh()和close(),让ApplicationContext具有启动、刷新和关闭上下文的能力。ApplicationContext在初始化上下文时就实例化所有的单例Bean.
WebApplicationContext:WebApplicationContext是专门为WEB应用而准备的,它允许从相对于WEB根目录的路径中完成初始化工作。
最常用的两个实现类:
ClassPathXmlApplicationContext : 从类路径下加载配置文件。
FileSystemXmlApplicationContext : 从文件系统中加载配置文件。
两个都是继承ConfigurableApplicationContext
bean标记的使用? 1 <bean id ="Bean 唯一标志符" class ="包名+类名" p:普通属性 ="普通属性值" p:对象属性-ref ="对象的引用" >
Spring 框架提供了 2 种短命名空间,可以简化 Spring 的 XML 配置,如下表。
短命名空间 简化的 XML 配置 说明 p 命名空间 元素中嵌套的元素 是 setter 方式属性注入的一种快捷实现方式 c 命名空间 元素中嵌套的元素 是构造函数属性注入的一种快捷实现方式
bean的范围有哪些? Spring 5 共提供了 6 种 scope 作用域,如下表。
作用范围 描述 singleton 默认值,单例模式,表示在 Spring 容器中只有一个 Bean 实例 prototype 原型模式,表示每次通过 Spring 容器获取 Bean 时,容器都会创建一个新的 Bean 实例。 request 每次 HTTP 请求,容器都会创建一个 Bean 实例。该作用域只在当前 HTTP Request 内有效。 session 同一个 HTTP Session 共享一个 Bean 实例,不同的 Session 使用不同的 Bean 实例。该作用域仅在当前 HTTP Session 内有效。 application 同一个 Web 应用共享一个 Bean 实例,该作用域在当前 ServletContext 内有效。 与 singleton 类似,但 singleton 表示每个 IoC 容器中仅有一个 Bean 实例,而一个 Web 应用中可能会存在多个 IoC 容器,但一个 Web 应用只会有一个 ServletContext,也可以说 application 才是 Web 应用中货真价实的单例模式。 websocket websocket 的作用域是 WebSocket ,即在整个 WebSocket 中有效。
如何获取bean? 在初始化时保存ApplicationContext对象 通过Spring提供的utils类获取ApplicationContext对象 继承自抽象类ApplicationObjectSupport 继承自抽象类WebApplicationObjectSupport 实现接口ApplicationContextAware 通过Spring提供的ContextLoader bean的生命周期和生命周期方法? 在传统的 Java 应用中,Bean 的生命周期很简单,使用 Java 关键字 new 进行 Bean 的实例化后,这个 Bean 就可以使用了。一旦这个 Bean 长期不被使用,Java 自动进行垃圾回收。
相比之下,Spring 中 Bean 的生命周期较复杂,大致可以分为以下 5 个阶段:
Bean 的实例化 Bean 属性赋值 Bean 的初始化 Bean 的使用 Bean 的销毁 Spring 根据 Bean 的作用域来选择 Bean 的管理方式,
对于 singleton 作用域的 Bean 来说,Spring IoC 容器能够精确地控制 Bean 何时被创建、何时初始化完成以及何时被销毁; 对于 prototype 作用域的 Bean 来说,Spring IoC 容器只负责创建,然后就将 Bean 的实例交给客户端代码管理,Spring IoC 容器将不再跟踪其生命周期。 Bean 的生命周期回调方法主要有两种:
初始化回调方法:在 Spring Bean 被初始化后调用,执行一些自定义的回调操作。 销毁回调方法:在 Spring Bean 被销毁前调用,执行一些自定义的回调操作。 通过接口实现
1 2 3 4 5 6 7 8 9 10 11 12 @Override public void afterPropertiesSet () throws Exception { System.out .println("【InitializingBean接口】调用InitializingBean.afterPropertiesSet()" ); }@Override public void destroy () throws Exception { System.out.println("【DiposibleBean接口】调用DiposibleBean.destory()" ); }
通过XML配置实现
1 2 3 4 5 6 7 public void myInit () { System.out.println("【init-method】调用<bean>的init-method属性指定的初始化方法" ); }public void myDestory () { System.out.println("【destroy-method】调用<bean>的destroy-method属性指定的初始化方法" ); }
1 2 3 <bean id ="person" class ="springBeanTest.Person" init-method ="myInit" destroy-method ="myDestory" scope ="singleton" p:name ="张三" p:address ="广州" p:phone ="15900000000" />
通过注解实现
注解 描述 @PostConstruct 指定初始化回调方法,这个方法会在 Spring Bean 被初始化后被调用,执行一些自定义的回调操作。 @PreDestroy 指定销毁回调方法,这个方法会在 Spring Bean 被销毁前被调用,执行一些自定义的回调操作。
通过后置处理器实现
1 2 3 4 public interface BeanPostProcessor { Object postProcessBeforeInitialization (Object bean, String beanName) throws BeansException; Object postProcessAfterInitialization (Object bean, String beanName) throws BeansException; }
两种显式装配? 构造函数注入
使用构造函数实现属性注入大致步骤如下:
在 Bean 中添加一个有参构造函数,构造函数内的每一个参数代表一个需要注入的属性; 在 Spring 的 XML 配置文件中,通过 <beans>
及其子元素 <bean>
对 Bean 进行定义; 在 <bean>
元素内使用 <constructor-arg>
元素,对构造函数内的属性进行赋值,Bean 的构造函数内有多少参数,就需要使用多少个 <constructor-arg>
元素。 setter注入
使用 setter 注入的方式进行属性注入,大致步骤如下:
在 Bean 中提供一个默认的无参构造函数(在没有其他带参构造函数的情况下,可省略),并为所有需要注入的属性提供一个 setXxx() 方法; 在 Spring 的 XML 配置文件中,使用 <beans>
及其子元素 <bean>
对 Bean 进行定义; 在 <bean>
元素内使用 <property>
元素对各个属性进行赋值。 value和ref的区别? value用于注入字面量属性,ref用于注入引用属性
如何注入集合? 标签说明用于注入 list 类型的值,允许重复用于注入 set 类型的值,不允许重复用于注入 key-value 的集合,其中 key 和 value 都可以是任意类型用于注入 key-value 的集合,其中 key 和 value 都是字符串类型
标签 说明 <list>
用于注入 list 类型的值,允许重复 <set>
用于注入 set 类型的值,不允许重复 <map>
用于注入 key-value 的集合,其中 key 和 value 都可以是任意类型 <props>
用于注入 key-value 的集合,其中 key 和 value 都是字符串类型
构造函数注入? 1 2 3 4 <bean id ="bean名" class ="类" > <constructor-arg name ="属性名" value ="值" /> <constructor-arg name ="属性名" ref ="引用" /> </bean >
或使用c:命名空间
parent属性的作用? 在 Spring XML 配置中,我们通过子 Bean 的 parent 属性来指定需要继承的父 Bean,配置格式如下。
1 2 3 4 5 6 7 <bean id ="parentBean" class ="xxx.xxxx.xxx.ParentBean" > <property name ="xxx" value ="xxx" /> <property name ="xxx" value ="xxx" /> </bean > <bean id ="childBean" class ="xxx.xxx.xxx.ChildBean" parent ="parentBean" />
如何使用工厂方法实现DI? 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 public class AnimalFactory { public static Animal getAnimal1 () { System.out.println("调用AnimalFactory类的静态工厂方法getAnimal1()................." ); return new Dog (); } public Animal getAnimal2 () { System.out.println("调用AnimalFactory类的实例工厂方法getAnimal2()................." ); return new Pig (); } private static Map<Integer,Animal> map; static { map=new HashMap <>(); map.put(1 ,new Dog ()); map.put(2 ,new Pig ()); map.put(3 ,new Sheep ()); } public static Animal getAnimal3 (int type) { System.out.println("调用AnimalFactory类的静态工厂方法getAnimal3()................." ); return map.get(type); } }
使用静态工厂方法返回自身实例
1 2 3 4 5 <bean class ="com.qdu.bean.A" factory-method ="getA" />
使用静态工厂方法返回其他类实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <bean id ="animal" class ="com.qdu.bean.AnimalFactory" factory-method ="getAnimal1" /> <bean id ="animal" class ="com.qdu.bean.AnimalFactory" factory-method ="getAnimal3" > <constructor-arg name ="type" value ="2" /> </bean >
使用非静态工厂方法返回其他类实例(不考)
1 2 3 4 5 6 7 8 9 10 11 12 <bean id ="animalFactory" class ="com.qdu.bean.AnimalFactory" /> <bean id ="animal" factory-bean ="animalFactory" factory-method ="getAnimal2" />
在java中获取bean
1 2 3 4 5 public static void main (String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext ("config/beans1.xml" ); A a = ctx.getBean(A.class); a.methodOfA(); }
自动装配的模式有哪些? Spring 共提供了 5 中自动装配规则,它们分别与 autowire 属性的 5 个取值对应,具体说明如下表。
属性值 说明 byName 按名称自动装配。 Spring 会根据的 Java 类中对象属性的名称,在整个应用的上下文 ApplicationContext(IoC 容器)中查找。若某个 Bean 的 id 或 name 属性值与这个对象属性的名称相同,则获取这个 Bean,并与当前的 Java 类 Bean 建立关联关系。 byType 按类型自动装配。 Spring 会根据 Java 类中的对象属性的类型,在整个应用的上下文 ApplicationContext(IoC 容器)中查找。若某个 Bean 的 class 属性值与这个对象属性的类型相匹配,则获取这个 Bean,并与当前的 Java 类的 Bean 建立关联关系。 constructor 与 byType 模式相似,不同之处在与它应用于构造器参数(依赖项),如果在容器中没有找到与构造器参数类型一致的 Bean,那么将抛出异常。 其实就是根据构造器参数的数据类型,进行 byType 模式的自动装配。 default 表示默认采用上一级元素设置的自动装配规则(default-autowire)进行装配。 no 默认值,表示不使用自动装配,Bean 的依赖关系必须通过和元素的 ref 属性来定义。
基于注解的自动装配
1 2 <context:component-scan base-package ="" />
显式装配与自动装配的关系? 显式装配是在 XML 配置中通过和中的 ref 属性,手动维护 Bean 与 Bean 之间的依赖关系的。
Spring 的自动装配功能可以让 Spring 容器依据某种规则(自动装配的规则,有五种),为指定的 Bean 从应用的上下文(AppplicationContext 容器)中查找它所依赖的 Bean,并自动建立 Bean 之间的依赖关系。而这一过程是在完全不使用任何和元素 ref 属性的情况下进行的。
依赖注入使用哪些注解? Spring 提供了以下多个注解,这些注解可以直接标注在 Java 类上,将它们定义成 Spring Bean。
注解 说明 @Component 该注解用于描述 Spring 中的 Bean,它是一个泛化的概念,仅仅表示容器中的一个组件(Bean),并且可以作用在应用的任何层次,例如 Service 层、Dao 层等。 使用时只需将该注解标注在相应类上即可。 @Repository 该注解用于将数据访问层(Dao 层)的类标识为 Spring 中的 Bean,其功能与 @Component 相同。 @Service 该注解通常作用在业务层(Service 层),用于将业务层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。 @Controller 该注解通常作用在控制层(如 Struts2 的 Action、SpringMVC 的 Controller),用于将控制层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。
我们可以通过以下注解将定义好 Bean 装配到其它的 Bean 中。
注解 说明 @Autowired 可以应用到 Bean 的属性变量、setter 方法、非 setter 方法及构造函数等,默认按照 Bean 的类型进行装配。 @Autowired 注解默认按照 Bean 的类型进行装配,默认情况下它要求依赖对象必须存在,如果允许 null 值,可以设置它的 required 属性为 false。如果我们想使用按照名称(byName)来装配,可以结合 @Qualifier 注解一起使用 @Resource 作用与 Autowired 相同,区别在于 @Autowired 默认按照 Bean 类型装配,而 @Resource 默认按照 Bean 的名称进行装配。 @Resource 中有两个重要属性:name 和 type。 Spring 将 name 属性解析为 Bean 的实例名称,type 属性解析为 Bean 的实例类型。如果指定 name 属性,则按实例名称进行装配;如果指定 type 属性,则按 Bean 类型进行装配;如果都不指定,则先按 Bean 实例名称装配,如果不能匹配,则再按照 Bean 类型进行装配;如果都无法匹配,则抛出 NoSuchBeanDefinitionException 异常。 @Qualifier 与 @Autowired 注解配合使用,会将默认的按 Bean 类型装配修改为按 Bean 的实例名称装配,Bean 的实例名称由 @Qualifier 注解的参数指定。
@Configuration和@Bean注解的作用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 @Configuration public class MyConfig { @Bean public MyBean myBean () { return new MyBean (); } @Bean public MyBean myBean1 () { return new MyBean (); } }
什么是AOP? AOP 的全称是“Aspect Oriented Programming”,译为“面向切面编程”,和 OOP(面向对象编程)类似,它也是一种编程思想。
通知的概念? AOP的一套术语
名称 说明 Joinpoint(连接点) AOP 的核心概念,指的是程序执行期间明确定义的一个点,例如方法的调用、类初始化、对象实例化等。 在 Spring 中,连接点则指可以被动态代理拦截目标类的方法。 Pointcut(切入点) 又称切点,指要对哪些 Joinpoint 进行拦截,即被拦截的连接点。 Advice(通知) 指拦截到 Joinpoint 之后要执行的代码,即对切入点增强的内容。 Target(目标) 指代理的目标对象,通常也被称为被通知(advised)对象。 Weaving(织入) 指把增强代码应用到目标对象上,生成代理对象的过程。 Proxy(代理) 指生成的代理对象。 Aspect(切面) 切面是切入点(Pointcut)和通知(Advice)的结合。
连接点的概念? 见上条
通知的类型(位置)? 共有5种:
通知 说明 before(前置通知) 通知方法在目标方法调用之前执行 after(后置通知) 通知方法在目标方法返回或异常后调用 after-returning(返回后通知) 通知方法会在目标方法返回后调用 after-throwing(抛出异常通知) 通知方法会在目标方法抛出异常后调用 around(环绕通知) 通知方法会将目标方法封装起来
用来创建通知的注解有哪些? 名称 说明 @Aspect 用于定义一个切面。 @Pointcut 用于定义一个切入点。 @Before 用于定义前置通知,相当于 BeforeAdvice。 @AfterReturning 用于定义后置通知,相当于 AfterReturningAdvice。 @Around 用于定义环绕通知,相当于 MethodInterceptor。 @AfterThrowing 用于定义抛出通知,相当于 ThrowAdvice。 @After 用于定义最终通知,不管是否异常,该通知都会执行。 @DeclareParents 用于定义引介通知,相当于 IntroductionInterceptor(不要求掌握)。
如何声明切入点? 1 2 3 4 5 6 7 @Pointcut("execution(* com.savage.aop.MessageSender.*(..))") private void log () {}
在返回后通知中如何获取目标方法的返回值? 1 2 3 4 @AfterReturning(value = "pt()",returning = "ret") public void afterReturning (Object ret) { System.out.println("afterReturning advice ..." +ret); }
XML如何配置AOP? 在 Spring 的 XML 配置文件中,添加以下内容启用 @AspectJ 注解支持。
1 2 3 4 <context:component-scan base-package ="" /> <aop:aspectj-autoproxy />
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 <bean id ="logAspect1" class ="com.qdu.aop.LogAspect1" /> <bean id ="logAspect2" class ="com.qdu.aop.LogAspect2" /> <bean class ="com.qdu.service.impl.StudentServiceImpl" /> <bean class ="com.qdu.service.impl.TeacherServiceImpl" /> <bean class ="com.qdu.service.impl.MathServiceImpl" /> <aop:config > <aop:pointcut expression ="execution(* com.qdu.service.StudentService.*(..))" id ="pt1" /> <aop:aspect ref ="logAspect1" order ="2" > <aop:pointcut expression ="execution(* com.qdu.service.MathService.add(..))" id ="pt2" /> <aop:pointcut expression ="execution(* com.qdu.service.MathService.divide(..))" id ="pt3" /> <aop:pointcut expression ="execution(* com.qdu.service.MathService.multiply(..))" id ="pt4" /> <aop:before method ="before1" pointcut-ref ="pt1" /> <aop:before method ="before2" pointcut-ref ="pt1" /> <aop:after-returning method ="afterReturning" pointcut-ref ="pt2" returning ="returnValue" /> <aop:after-throwing method ="afterThrowing" pointcut-ref ="pt3" throwing ="ex" /> <aop:after method ="after" pointcut-ref ="pt3" /> <aop:around method ="around" pointcut-ref ="pt4" /> </aop:aspect > <aop:aspect ref ="logAspect2" order ="1" > <aop:before method ="before3" pointcut-ref ="pt1" /> <aop:before method ="before4" pointcut-ref ="pt1" /> </aop:aspect > </aop:config >
JDBC Template的CRUD操作有哪些? 方法 说明 public int update(String sql) 用于执行新增、更新、删除等语句;sql:需要执行的 SQL 语句;args 表示需要传入到 SQL 语句中的参数。 public int update(String sql,Object… args) public void execute(String sql) 可以执行任意 SQL,一般用于执行 DDL 语句; sql:需要执行的 SQL 语句;action 表示执行完 SQL 语句后,要调用的函数。 public T execute(String sql, PreparedStatementCallback action) publicListquery(String sql, RowMapperrowMapper, @Nullable Object… args) 用于执行查询语句;sql:需要执行的 SQL 语句;rowMapper:用于确定返回的集合(List)的类型;args:表示需要传入到 SQL 语句的参数。 publicT queryForObject(String sql, RowMapperrowMapper, @Nullable Object… args) public int[] batchUpdate(String sql, List<Object[]> batchArgs, final int[] argTypes) 用于批量执行新增、更新、删除等语句; sql:需要执行的 SQL 语句;argTypes:需要注入的 SQL 参数的 JDBC 类型;batchArgs:表示需要传入到 SQL 语句的参数。
如何创建处理全局异常? 局部异常
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @ExceptionHandler({ArithmeticException.class,NumberFormatException.class}) public String handleException (Model model, Throwable ex) { logger.error("发生异常,异常消息: " +ex.getMessage()); model.addAttribute("msg" , "局部异常处理程序,异常消息: " +ex.getMessage()); return "error" ; }
全局异常
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 @ControllerAdvice public class GlobalExceptionHandler { private static Logger logger=LoggerFactory.getLogger(GlobalExceptionHandler.class); @ExceptionHandler({ArithmeticException.class}) public String handleException (Model model, ArithmeticException e) { logger.error("全局异常处理程序:程序发生异常,异常消息-" +e.getMessage()); model.addAttribute("msg" , "全局异常处理程序,异常消息: " +e.getMessage()); return "error" ; } @ExceptionHandler({IOException.class,ArrayIndexOutOfBoundsException.class}) @ResponseBody public String exceptionHandler2 (Throwable ex) { return "Exception occurred, exception message: " +ex.getMessage(); } }
JDBC Template 和 NamedParameterJDBCTemplate的区别 JDBC Template:最基本的JDBC模板,支持基于索引参数(?
)的查询
NamedParameterJdbcTemplate:使用该模板类执行查询的时候使用命名参数的方式绑定到SQL而不是索引参数
事务的特征? 事务具有 4 个特性:原子性、一致性、隔离性和持久性,简称为 ACID 特性。
原子性(Atomicity):一个事务是一个不可分割的工作单位,事务中包括的动作要么都做要么都不做。 一致性(Consistency):事务必须保证数据库从一个一致性状态变到另一个一致性状态,一致性和原子性是密切相关的。 隔离性(Isolation):一个事务的执行不能被其它事务干扰,即一个事务内部的操作及使用的数据对并发的其它事务是隔离的,并发执行的各个事务之间不能互相打扰。 持久性(Durability):持久性也称为永久性,指一个事务一旦提交,它对数据库中数据的改变就是永久性的,后面的其它操作和故障都不应该对其有任何影响。 事务的传播行为? 事务传播行为(propagation behavior)指的是,当一个事务方法被另一个事务方法调用时,这个事务方法应该如何运行。 Spring 提供了以下 7 种不同的事务传播行为。
名称 说明 PROPAGATION_MANDATORY 支持当前事务,如果不存在当前事务,则引发异常。 PROPAGATION_NESTED 如果当前事务存在,则在嵌套事务中执行。 PROPAGATION_NEVER 不支持当前事务,如果当前事务存在,则引发异常。 PROPAGATION_NOT_SUPPORTED 不支持当前事务,始终以非事务方式执行。 PROPAGATION_REQUIRED 默认传播行为,如果存在当前事务,则当前方法就在当前事务中运行,如果不存在,则创建一个新的事务,并在这个新建的事务中运行。 PROPAGATION_REQUIRES_NEW 创建新事务,如果已经存在事务则暂停当前事务。 PROPAGATION_SUPPORTS 支持当前事务,如果不存在事务,则以非事务方式执行。
事务并发可能导致的问题? 事务的隔离级别定义了一个事务可能受其他并发事务影响的程度。
在实际应用中,经常会出现多个事务同时对同一数据执行不同操作,来实现各自的任务的情况。此时就有可能导致脏读、幻读以及不可重复读等问题的出现。
在理想情况下,事务之间是完全隔离的,这自然不会出现上述问题。但完全的事务隔离会导致性能问题,而且并不是所有的应用都需要事务的完全隔离,因此有时应用程序在事务隔离上也有一定的灵活性。
Spring 中提供了以下隔离级别,我们可以根据自身的需求自行选择合适的隔离级别。
方法 说明 ISOLATION_DEFAULT 使用后端数据库默认的隔离级别 ISOLATION_READ_UNCOMMITTED 允许读取尚未提交的更改,可能导致脏读、幻读和不可重复读 ISOLATION_READ_COMMITTED Oracle 默认级别,允许读取已提交的并发事务,防止脏读,可能出现幻读和不可重复读 ISOLATION_REPEATABLE_READ MySQL 默认级别,多次读取相同字段的结果是一致的,防止脏读和不可重复读,可能出现幻读 ISOLATION_SERIALIZABLE 完全服从 ACID 的隔离级别,防止脏读、不可重复读和幻读
Spring 并不会直接管理事务,而是通过事务管理器对事务进行管理的。
在 Spring 中提供了一个 org.springframework.transaction.PlatformTransactionManager 接口,这个接口被称为 Spring 的事务管理器,其源码如下。
1 2 3 4 5 6 7 public interface PlatformTransactionManager extends TransactionManager { TransactionStatus getTransaction (@Nullable TransactionDefinition definition) throws TransactionException; void commit (TransactionStatus status) throws TransactionException; void rollback (TransactionStatus status) throws TransactionException; }
该接口中各方法说明如下:
名称 说明 TransactionStatus getTransaction(TransactionDefinition definition) 用于获取事务的状态信息 void commit(TransactionStatus status) 用于提交事务 void rollback(TransactionStatus status) 用于回滚事务
Spring 为不同的持久化框架或平台(例如 JDBC、Hibernate、JPA 以及 JTA 等)提供了不同的 PlatformTransactionManager 接口实现,这些实现类被称为事务管理器实现。
实现类 说明 org.springframework. jdbc.datasource. DataSourceTransactionManager 使用 Spring JDBC 或 iBatis 进行持久化数据时使用。 org.springframework. orm.hibernate3. HibernateTransactionManager 使用 Hibernate 3.0 及以上版本进行持久化数据时使用。 org.springframework .orm.jpa. JpaTransactionManager 使用 JPA 进行持久化时使用。 org.springframework .jdo. JdoTransactionManager 当持久化机制是 Jdo 时使用。 org.springframework. transaction. jta.JtaTransactionManager 使用 JTA 来实现事务管理,在一个事务跨越多个不同的资源(即分布式事务)使用该实现。
这些事务管理器的使用方式十分简单,我们只要根据持久化框架(或平台)选用相应的事务管理器实现,即可实现对事物的管理,而不必关心实际事务实现到底是什么。
如何使用XML配置事务? 1. 引入 tx 命名空间 Spring 提供了一个 tx 命名空间,借助它可以极大地简化 Spring 中的声明式事务的配置。
想要使用 tx 命名空间,第一步就是要在 XML 配置文件中添加 tx 命名空间的约束。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?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-3.0.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" >
注意: 由于 Spring 提供的声明式事务管理是依赖于 Spring AOP 实现的,因此我们在 XML 配置文件中还应该添加与 aop 命名空间相关的配置。
2. 配置事务管理器 接下来,我们就需要借助数据源配置,定义相应的事务管理器实现(PlatformTransactionManager 接口的实现类)的 Bean,配置内容如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <bean id ="dataSource" class ="org.springframework.jdbc.datasource.DriverManagerDataSource" > <property name ="url" value ="xxx" /> <property name ="username" value ="xxx" /> <property name ="password" value ="xxx" /> <property name ="driverClassName" value ="xxx" /> </bean > <bean id ="transactionManager" class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" > <property name ="dataSource" ref ="dataSource" /> </bean >
在以上配置中,配置的事务管理器实现为 DataSourceTransactionManager,即为 JDBC 和 iBatis 提供的 PlatformTransactionManager 接口实现。
3. 配置事务通知 在 Spring 的 XML 配置文件中配置事务通知,指定事务作用的方法以及所需的事务属性。
1 2 3 4 5 6 7 <tx:advice id ="tx-advice" transaction-manager ="transactionManager" > <tx:attributes > <tx:method name ="create*" propagation ="REQUIRED" isolation ="DEFAULT" read-only ="false" timeout ="10" /> </tx:attributes > </tx:advice >
事务管理器配置 当我们使用 tx:advice 来声明事务时,需要通过 transaction-manager 参数来定义一个事务管理器,这个参数的取值默认为 transactionManager。
如果我们自己设置的事务管理器(第 2 步中设置的事务管理器 id)恰好与默认值相同,则可以省略对改参数的配置。
1 2 3 4 5 6 <tx:advice id ="tx-advice" > <tx:attributes > <tx:method name ="create*" propagation ="REQUIRED" isolation ="DEFAULT" read-only ="false" timeout ="10" /> </tx:attributes > </tx:advice >
但如果我们自己设置的事务管理器 id 与默认值不同,则必须手动在 tx:advice 元素中通过 transaction-manager 参数指定。
事务属性配置 对于tx:advice 来说,事务属性是被定义在tx:attributes 中的,该元素可以包含一个或多个 tx:method 元素。
tx:method 元素包含多个属性参数,可以为某个或某些指定的方法(name 属性定义的方法)定义事务属性,如下表所示。
事务属性 说明 propagation 指定事务的传播行为。 isolation 指定事务的隔离级别。 read-only 指定是否为只读事务。 timeout 表示超时时间,单位为“秒”;声明的事务在指定的超时时间后,自动回滚,避免事务长时间不提交会回滚导致的数据库资源的占用。 rollback-for 指定事务对于那些类型的异常应当回滚,而不提交。 no-rollback-for 指定事务对于那些异常应当继续运行,而不回滚。
4. 配置切点切面 tx:advice 元素只是定义了一个 AOP 通知,它并不是一个完整的事务性切面。我们在 tx:advice 元素中并没有定义哪些 Bean 应该被通知,因此我们需要一个切点来做这件事。
在 Spring 的 XML 配置中,我们可以利用 Spring AOP 技术将事务通知(tx-advice)和切点配置到切面中,配置内容如下。
1 2 3 4 5 6 7 <aop:config > <aop:pointcut id ="tx-pt" expression ="execution(* net.biancheng.c.service.impl.OrderServiceImpl.*(..))" /> <aop:advisor advice-ref ="tx-advice" pointcut-ref ="tx-pt" > </aop:advisor > </aop:config >
如何启用注解驱动的事务编程模型? 1. 开启注解事务 tx 命名空间提供了一个 tx:annotation-driven 元素,用来开启注解事务,简化 Spring 声明式事务的 XML 配置。
tx:annotation-driven 元素的使用方式也十分的简单,我们只要在 Spring 的 XML 配置中添加这样一行配置即可。
1 <tx:annotation-driven transaction-manager ="transactionManager" > </tx:annotation-driven >
与 tx:advice 元素一样,tx:annotation-driven 也需要通过 transaction-manager 属性来定义一个事务管理器,这个参数的取值默认为 transactionManager。如果我们使用的事务管理器的 id 与默认值相同,则可以省略对该属性的配置,形式如下。
通过 tx:annotation-driven 元素开启注解事务后,Spring 会自动对容器中的 Bean 进行检查,找到使用 @Transactional 注解的 Bean,并为其提供事务支持。
2. 使用 @Transactional 注解 @Transactional 注解是 Spring 声明式事务编程的核心注解,该注解既可以在类上使用,也可以在方法上使用。
1 2 3 4 5 6 7 8 9 10 11 12 @Transactional public class XXX { @Transactional public void A (Order order) { …… } public void B (Order order) { …… } }
若 @Transactional 注解在类上使用,则表示类中的所有方法都支持事务;若 @Transactional 注解在方法上使用,则表示当前方法支持事务。
Spring 在容器中查找所有使用了 @Transactional 注解的 Bean,并自动为它们添加事务通知,通知的事务属性则是通过 @Transactional 注解的属性来定义的。
@Transactional 注解包含多个属性,其中常用属性如下表。
事务属性 说明 propagation 指定事务的传播行为。 isolation 指定事务的隔离级别。 read-only 指定是否为只读事务。 timeout 表示超时时间,单位为“秒”;声明的事务在指定的超时时间后,自动回滚,避免事务长时间不提交会回滚导致的数据库资源的占用。 rollback-for 指定事务对于那些类型的异常应当回滚,而不提交。 no-rollback-for 指定事务对于那些异常应当继续运行,而不回滚。
SQLSessionFactory的创建与使用? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class MybatisUtil { private static SqlSessionFactory sqlSessionFactory; static { try { InputStream is = Resources.getResourceAsStream("config/mybatis-config.xml" ); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder (); sqlSessionFactory = builder.build(is); } catch (IOException ex) { ex.printStackTrace(); } } public static SqlSessionFactory getSqlSessionFactory () { return sqlSessionFactory; } public static SqlSession openSession () { return sqlSessionFactory.openSession(); } }
如何使用Java类替换web.xml? 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 public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class [] { SpringConfig.class }; } @Override protected Class<?>[] getServletConfigClasses() { return new Class [] { SpringMvcConfig.class }; } @Override protected String[] getServletMappings() { return new String [] { "/" }; } @Override protected Filter[] getServletFilters() { return new Filter [] { new CharacterEncodingFilter ("utf-8" ,true ,true ) }; } }
springApplication.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 @Configuration @ComponentScan(basePackages= {"com.qdu.service"}) @PropertySource({"classpath:config/jdbc.properties"}) @MapperScan(basePackages= {"com.qdu.mapper"}) @EnableTransactionManagement public class SpringConfig { @Autowired Environment env; @Bean public DruidDataSource dataSource () { DruidDataSource dataSource = new DruidDataSource (); dataSource.setDriverClassName(env.getProperty("jdbc.driver" )); dataSource.setUrl(env.getProperty("jdbc.url" )); dataSource.setUsername(env.getProperty("jdbc.username" )); dataSource.setPassword(env.getProperty("jdbc.password" )); dataSource.setInitialSize(Integer.parseInt(env.getProperty("initialSize" ))); dataSource.setMaxActive(Integer.parseInt(env.getProperty("maxActive" ))); dataSource.setMaxWait(Integer.parseInt(env.getProperty("maxWait" ))); dataSource.setMinIdle(Integer.parseInt(env.getProperty("minIdle" ))); dataSource.setTimeBetweenEvictionRunsMillis(Long.parseLong(env.getProperty("timeBetweenEvictionRunsMillis" ))); dataSource.setMinEvictableIdleTimeMillis(Long.parseLong(env.getProperty("minEvictableIdleTimeMillis" ))); dataSource.setValidationQuery(env.getProperty("validationQuery" )); dataSource.setTestWhileIdle(Boolean.parseBoolean(env.getProperty("minEvictableIdleTimeMillis" ))); dataSource.setTestOnBorrow(Boolean.parseBoolean(env.getProperty("testOnBorrow" ))); dataSource.setTestOnReturn(Boolean.parseBoolean(env.getProperty("testOnReturn" ))); return dataSource; } @Bean public SqlSessionFactory sqlSessionFactory (DataSource ds) throws Exception { SqlSessionFactoryBean factoryBean=new SqlSessionFactoryBean (); factoryBean.setDataSource(ds); factoryBean.setTypeAliasesPackage("com.qdu.entity" ); return factoryBean.getObject(); } @Bean public DataSourceTransactionManager txManager (DataSource ds) { return new DataSourceTransactionManager (ds); } }
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 32 33 34 35 36 37 38 39 40 41 42 43 @Configuration @ComponentScan(basePackages = {"com.qdu.controller"}) @EnableWebMvc public class SpringMvcConfig implements WebMvcConfigurer { @Override public void addResourceHandlers (ResourceHandlerRegistry registry) { registry.addResourceHandler("/static/**" ).addResourceLocations("/static/" ); } @Override public void addViewControllers (ViewControllerRegistry registry) { registry.addViewController("/" ).setViewName("index" ); registry.addViewController("/index" ).setViewName("index" ); } @Bean public SpringResourceTemplateResolver templateResolver () { SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver (); templateResolver.setPrefix("/WEB-INF/templates/" ); templateResolver.setSuffix(".html" ); templateResolver.setTemplateMode(TemplateMode.HTML); templateResolver.setCacheable(false ); templateResolver.setCharacterEncoding("UTF-8" ); return templateResolver; } @Bean public SpringTemplateEngine templateEngine () { SpringTemplateEngine templateEngine = new SpringTemplateEngine (); templateEngine.setTemplateResolver(templateResolver()); templateEngine.setEnableSpringELCompiler(true ); return templateEngine; } @Bean public ThymeleafViewResolver viewResolver () { ThymeleafViewResolver viewResolver = new ThymeleafViewResolver (); viewResolver.setTemplateEngine(templateEngine()); viewResolver.setCharacterEncoding("UTF-8" ); return viewResolver; } }
如何集成SSM? java配置类配置ssm 见上条
xml配置ssm 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 <?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_4_0.xsd" version ="4.0" > <listener > <listener-class > org.springframework.web.context.ContextLoaderListener</listener-class > </listener > <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 > <context-param > <param-name > contextConfigLocation</param-name > <param-value > classpath:config/spring-config.xml</param-value > </context-param > <servlet > <servlet-name > dispatcher</servlet-name > <servlet-class > org.springframework.web.servlet.DispatcherServlet</servlet-class > <init-param > <param-name > contextConfigLocation</param-name > <param-value > classpath:config/spring-mvc.xml</param-value > </init-param > <load-on-startup > 1</load-on-startup > </servlet > <servlet-mapping > <servlet-name > dispatcher</servlet-name > <url-pattern > /</url-pattern > </servlet-mapping > <session-config > <session-timeout > 30 </session-timeout > </session-config > </web-app >
spring-config
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 <beans 略 > <context:component-scan base-package ="com.qdu.service" /> <context:property-placeholder location ="classpath:config/jdbc.properties" /> <bean id ="dataSource" class ="com.alibaba.druid.pool.DruidDataSource" init-method ="init" destroy-method ="close" > <property name ="driverClassName" value ="${jdbc.driverClass}" /> <property name ="url" value ="${jdbc.url}" /> <property name ="username" value ="${jdbc.username}" /> <property name ="password" value ="${jdbc.password}" /> <property name ="initialSize" value ="${initialSize}" /> <property name ="maxActive" value ="${maxActive}" /> <property name ="maxWait" value ="${maxWait}" /> <property name ="minIdle" value ="${minIdle}" /> <property name ="timeBetweenEvictionRunsMillis" value ="${timeBetweenEvictionRunsMillis}" /> <property name ="minEvictableIdleTimeMillis" value ="${minEvictableIdleTimeMillis}" /> <property name ="validationQuery" value ="${validationQuery}" /> <property name ="testWhileIdle" value ="${testWhileIdle}" /> <property name ="testOnBorrow" value ="${testOnBorrow}" /> <property name ="testOnReturn" value ="${testOnReturn}" /> </bean > <bean id ="sqlSessionFactory" class ="org.mybatis.spring.SqlSessionFactoryBean" > <property name ="dataSource" ref ="dataSource" /> <property name ="typeAliasesPackage" value ="com.qdu.entity" /> </bean > <bean class ="org.mybatis.spring.mapper.MapperScannerConfigurer" > <property name ="basePackage" value ="com.qdu.mapper" /> </bean > <bean id ="txManager" class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" > <property name ="dataSource" ref ="dataSource" /> </bean > <tx:advice id ="txAdvice" transaction-manager ="txManager" > <tx:attributes > <tx:method name ="add*" propagation ="REQUIRED" /> <tx:method name ="update*" /> <tx:method name ="delete*" /> <tx:method name ="transfer*" /> <tx:method name ="get*" read-only ="true" /> </tx:attributes > </tx:advice > <aop:config > <aop:pointcut expression ="within(com.qdu.service..*)" id ="pt" /> <aop:advisor advice-ref ="txAdvice" pointcut-ref ="pt" /> </aop:config > </beans >
spring-mvc
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 <?xml version="1.0" encoding="UTF-8" ?> <beans 略 > <context:component-scan base-package ="com.qdu.controller" /> <mvc:annotation-driven /> <bean id ="templateResolver" class ="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver" > <property name ="prefix" value ="/WEB-INF/templates/" /> <property name ="suffix" value =".html" /> <property name ="templateMode" value ="HTML" /> <property name ="cacheable" value ="false" /> <property name ="characterEncoding" value ="UTF-8" /> </bean > <bean id ="templateEngine" class ="org.thymeleaf.spring5.SpringTemplateEngine" > <property name ="templateResolver" ref ="templateResolver" /> <property name ="enableSpringELCompiler" value ="true" /> </bean > <bean class ="org.thymeleaf.spring5.view.ThymeleafViewResolver" > <property name ="templateEngine" ref ="templateEngine" /> <property name ="characterEncoding" value ="UTF-8" /> </bean > <mvc:resources mapping ="/static/**" location ="/static/" /> <mvc:view-controller path ="/" view-name ="index" /> <mvc:view-controller path ="/index" view-name ="index" /> </beans >
如何配置Spring Security? 1.添加启动依赖
1 2 3 4 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-security</artifactId > </dependency >
2.配置spring security
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 @Configuration @EnableWebSecurity public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { @Bean public BCryptPasswordEncoder passwordEncoder () { return new BCryptPasswordEncoder (); } @Autowired private CustomUserDetailsService userDetailsService; @Override protected void configure (AuthenticationManagerBuilder auth) throws Exception { auth .userDetailsService(userDetailsService) .passwordEncoder(passwordEncoder()); } @Override public void configure (WebSecurity web) throws Exception { web.ignoring().antMatchers("/css/**" , "/js/**" , "/img/**" ); } @Override protected void configure (HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/" , "/index" , "/toLogin" , "/login_failed" ).permitAll() .antMatchers("/user/**" ).hasRole("user" ) .antMatchers("/admin/**" ).hasAnyRole("admin" , "sadmin" ) .antMatchers("/sadmin/**" ).hasRole("sadmin" ) .anyRequest().authenticated() .and() .formLogin() .loginPage("/toLogin" ) .failureUrl("/login_failed" ) .and() .rememberMe() .rememberMeCookieName("remember" ) .rememberMeParameter("rememberMe" ) .tokenValiditySeconds(7 * 24 * 60 * 60 ) .and() .httpBasic() .and() .csrf().disable(); } }
3.自定义security功能
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 @Component public class CustomUserDetailsService implements UserDetailsService { @Autowired private UserInfoMapper mapper; @Override public UserDetails loadUserByUsername (String username) throws UsernameNotFoundException { UserInfo userinfo=mapper.selectByPrimaryKey(username); if (null ==userinfo) throw new UsernameNotFoundException ("无此用户" ); List<String> roles=mapper.selectRoleNamesById(username); List<GrantedAuthority> authorities=new ArrayList <>(); for (String role:roles) { authorities.add(new SimpleGrantedAuthority ("ROLE_" +role)); } return new User (userinfo.getUid(),userinfo.getUpassword(),authorities); } }
spring MVC 12问 MVC模式的概念? MVC 设计模式一般指 MVC 框架,M(Model)指数据模型层,V(View)指视图层,C(Controller)指控制层。使用 MVC 的目的是将 M 和 V 的实现代码分离,使同一个程序可以有不同的表现形式。其中,View 的定义比较清晰,就是用户界面。
Spring MVC包含的组件及其作用? 1)DispatcherServlet DispatcherServlet 是前端控制器,从图 1 可以看出,Spring MVC 的所有请求都要经过 DispatcherServlet 来统一分发。DispatcherServlet 相当于一个转发器或中央处理器,控制整个流程的执行,对各个组件进行统一调度,以降低组件之间的耦合性,有利于组件之间的拓展。
2)HandlerMapping HandlerMapping 是处理器映射器,其作用是根据请求的 URL 路径,通过注解或者 XML 配置,寻找匹配的处理器(Handler)信息。
3)HandlerAdapter HandlerAdapter 是处理器适配器,其作用是根据映射器找到的处理器(Handler)信息,按照特定规则执行相关的处理器(Handler)。
4)Handler Handler 是处理器,和 Java Servlet 扮演的角色一致。其作用是执行相关的请求处理逻辑,并返回相应的数据和视图信息,将其封装至 ModelAndView 对象中。
5)View Resolver View Resolver 是视图解析器,其作用是进行解析操作,通过 ModelAndView 对象中的 View 信息将逻辑视图名解析成真正的视图 View(如通过一个 JSP 路径返回一个真正的 JSP 页面)。
6)View View 是视图,其本身是一个接口,实现类支持不同的 View 类型(JSP、FreeMarker、Excel 等)。
以上组件中,需要开发人员进行开发的是处理器(Handler,常称Controller)和视图(View)。通俗的说,要开发处理该请求的具体代码逻辑,以及最终展示给用户的界面。
Spring MVC处理请求的过程?
SpringMVC 的执行流程如下。
用户点击某个请求路径,发起一个 HTTP request 请求,该请求会被提交到 DispatcherServlet(前端控制器); 由 DispatcherServlet 请求一个或多个 HandlerMapping(处理器映射器),并返回一个执行链(HandlerExecutionChain)。 DispatcherServlet 将执行链返回的 Handler 信息发送给 HandlerAdapter(处理器适配器); HandlerAdapter 根据 Handler 信息找到并执行相应的 Handler(常称为 Controller); Handler 执行完毕后会返回给 HandlerAdapter 一个 ModelAndView 对象(Spring MVC的底层对象,包括 Model 数据模型和 View 视图信息); HandlerAdapter 接收到 ModelAndView 对象后,将其返回给 DispatcherServlet ; DispatcherServlet 接收到 ModelAndView 对象后,会请求 ViewResolver(视图解析器)对视图进行解析; ViewResolver 根据 View 信息匹配到相应的视图结果,并返回给 DispatcherServlet; DispatcherServlet 接收到具体的 View 视图后,进行视图渲染,将 Model 中的模型数据填充到 View 视图中的 request 域,生成最终的 View(视图); 视图负责将结果显示到浏览器(客户端)。 servlet合法的URL模式? servlet的url模式合法的写法有:
精准匹配 扩展名匹配 路径匹配/xxx/*
用于匹配路径包含xxx的所有请求,xxx可以是一级或者多级/*
匹配以/开头,任意结尾的请求url。 缺省匹配 如何配置DispatcherServlet? 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 <web-app > <listener > <listener-class > org.springframework.web.context.ContextLoaderListener</listener-class > </listener > <context-param > <param-name > contextConfigLocation</param-name > <param-value > /WEB-INF/app-context.xml</param-value > </context-param > <servlet > <servlet-name > app</servlet-name > <servlet-class > org.springframework.web.servlet.DispatcherServlet</servlet-class > <init-param > <param-name > contextConfigLocation</param-name > <param-value > </param-value > </init-param > <load-on-startup > 1</load-on-startup > </servlet > <servlet-mapping > <servlet-name > app</servlet-name > <url-pattern > /app/*</url-pattern > </servlet-mapping > </web-app >
Java配置:实现WebApplicationInitializer接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class MyWebApplicationInitializer implements WebApplicationInitializer { @Override public void onStartup (ServletContext servletCxt) { AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext (); ac.register(AppConfig.class); ac.refresh(); DispatcherServlet servlet = new DispatcherServlet (ac); ServletRegistration.Dynamic registration = servletCxt.addServlet("app" , servlet); registration.setLoadOnStartup(1 ); registration.addMapping("/app/*" ); } }
如何配置Spring MVC配置文件的位置? Spring MVC 配置:在 web.xml 中配置 Servlet,创建 Spring MVC 的配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <servlet > <servlet-name > dispatcherServlet</servlet-name > <servlet-class > org.springframework.web.servlet.DispatcherServlet</servlet-class > <init-param > <param-name > contextConfigLocation</param-name > <param-value > classpath:springMVC.xml</param-value > </init-param > <load-on-startup > 1</load-on-startup > </servlet >
Spring和Spring MVC配置文件的默认名称? springMVC配置文件默认名称:<servlet-name>-servlet.xml
servlet-name是在web.xml<servlet>
标签中定义的 spring配置文件名称:applicationContext.xml
如何配置视图解析器? in *-.servlet
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 <?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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd" > <context:component-scan base-package ="" /> <bean id ="viewResolver" class ="org.thymeleaf.spring5.view.ThymeleafViewResolver" > <property name ="order" value ="1" /> <property name ="characterEncoding" value ="UTF-8" /> <property name ="templateEngine" > <bean class ="org.thymeleaf.spring5.SpringTemplateEngine" > <property name ="templateResolver" > <bean class ="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver" > <property name ="prefix" value ="/WEB-INF/templates/" /> <property name ="suffix" value =".html" /> <property name ="templateMode" value ="HTML5" /> <property name ="characterEncoding" value ="UTF-8" /> </bean > </property > </bean > </property > </bean > </beans >
视图解析器(ViewResolver)是 Spring MVC 的重要组成部分,负责将逻辑视图名解析为具体的视图对象。
Spring MVC 提供了很多视图解析类,其中每一项都对应 Java Web 应用中特定的某些视图技术。下面介绍一些常用的视图解析类。
URLBasedViewResolver UrlBasedViewResolver 是对 ViewResolver 的一种简单实现,主要提供了一种拼接 URL 的方式来解析视图。
UrlBasedViewResolver 通过 prefix 属性指定前缀,suffix 属性指定后缀。当 ModelAndView 对象返回具体的 View 名称时,它会将前缀 prefix 和后缀 suffix 与具体的视图名称拼接,得到一个视图资源文件的具体加载路径,从而加载真正的视图文件并反馈给用户。
使用 UrlBasedViewResolver 除了要配置前缀和后缀属性之外,还需要配置“viewClass”,表示解析成哪种视图。示例代码如下
1 2 3 4 5 6 7 <bean id ="viewResolver" class ="org.springframework.web.servlet.view.UrlBasedViewResolver" > <property name ="viewClass" value ="org.springframework.web.servlet.view.InternalResourceViewResolver" /> <property name ="prefix" value ="/WEB-INF/jsp/" /> <property name ="suffix" value =".jsp" /> </bean >
InternalResourceViewResolver InternalResourceViewResolver 为“内部资源视图解析器”,是日常开发中最常用的视图解析器类型。它是 URLBasedViewResolver 的子类,拥有 URLBasedViewResolver 的一切特性。
InternalResourceViewResolver 能自动将返回的视图名称解析为 InternalResourceView 类型的对象。InternalResourceView 会把 Controller 处理器方法返回的模型属性都存放到对应的 request 属性中,然后通过 RequestDispatcher 在服务器端把请求 forword 重定向到目标 URL。也就是说,使用 InternalResourceViewResolver 视图解析时,无需再单独指定 viewClass 属性。示例代码如下。
1 2 3 4 5 6 7 <bean id ="viewResolver" class ="org.springframework.web.servlet.view.InternalResourceViewResolver" > <property name ="viewClass" value ="org.springframework.web.servlet.view.InternalResourceViewResolver" /> <property name ="prefix" value ="/WEB-INF/jsp/" /> <property name ="suffix" value =".jsp" /> </bean >
创建和使用控制器? @Controller 注解用于声明某类的实例是一个控制器。例如,创建控制器类 IndexController,示例代码如下
1 2 3 4 @Controller public class IndexController { }
Spring MVC 使用扫描机制找到应用中所有基于注解的控制器类,所以,为了让控制器类被 Spring MVC 框架扫描到,需要在配置文件中声明 spring-context,并使用 <context:component-scan/>
元素指定控制器类的基本包(请确保所有控制器类都在基本包及其子包下)。
例如,在 springmvcDemo 应用的配置文件 springmvc-servlet.xml 中添加以下代码:
1 2 <context:component-scan base-package ="com.example.controller" />
如何映射不同的请求? 在基于注解的控制器类中可以为每个请求编写对应的处理方法。使用 @RequestMapping 注解将请求与处理方法一 一对应即可。
@RequestMapping 注解可用于类或方法上。用于类上,表示类中的所有响应请求的方法都以该地址作为父路径。
@RequestMapping 注解常用属性如下。
1. value 属性 value 属性是 @RequestMapping 注解的默认属性,因此如果只有 value 属性时,可以省略该属性名,如果有其它属性,则必须写上 value 属性名称。如下。
1 2 3 @RequestMapping(value="toUser") @RequestMapping("toUser")
value 属性支持通配符匹配,如 @RequestMapping(value="toUser/*")
表示 http://localhost:8080/toUser/1 或 http://localhost:8080/toUser/hahaha 都能够正常访问。
2. path属性 path 属性和 value 属性都用来作为映射使用。即 @RequestMapping(value="toUser")
和 @RequestMapping(path="toUser")
都能访问 toUser() 方法。
path 属性支持通配符匹配,如 @RequestMapping(path="toUser/*")
表示 http://localhost:8080/toUser/1 或 http://localhost:8080/toUser/hahaha 都能够正常访问。
3. name属性 name属性相当于方法的注释,使方法更易理解。如 @RequestMapping(value = "toUser",name = "获取用户信息")
。
4. method属性 method 属性用于表示该方法支持哪些 HTTP 请求。如果省略 method 属性,则说明该方法支持全部的 HTTP 请求。
@RequestMapping(value = "toUser",method = RequestMethod.GET)
表示该方法只支持 GET 请求。
也可指定多个 HTTP 请求,如 @RequestMapping(value = "toUser",method = {RequestMethod.GET,RequestMethod.POST})
,说明该方法同时支持 GET 和 POST 请求。
5. params属性 params 属性用于指定请求中规定的参数,代码如下。
1 2 3 4 @RequestMapping(value = "toUser",params = "type") public String toUser () { return "showUser" ; }
以上代码表示请求中必须包含 type 参数时才能执行该请求。即 http://localhost:8080/toUser?type=xxx 能够正常访问 toUser() 方法,而 http://localhost:8080/toUser 则不能正常访问 toUser() 方法。
1 2 3 4 @RequestMapping(value = "toUser",params = "type=1") public String toUser () { return "showUser" ; }
以上代码表示请求中必须包含 type 参数,且 type 参数为 1 时才能够执行该请求。即 http://localhost:8080/toUser?type=1 能够正常访问 toUser() 方法,而 http://localhost:8080/toUser?type=2 则不能正常访问 toUser() 方法。
header 属性表示请求中必须包含某些指定的 header 值。
@RequestMapping(value = "toUser",headers = "Referer=http://www.xxx.com")
表示请求的 header 中必须包含了指定的“Referer”请求头,以及值为“http://www.xxx.com”时,才能执行该请求。
7. consumers属性 consumers 属性用于指定处理请求的提交内容类型(Content-Type),例如:application/json、text/html。如@RequestMapping(value = "toUser",consumes = "application/json")
。
8. produces属性 produces 属性用于指定返回的内容类型,返回的内容类型必须是 request 请求头(Accept)中所包含的类型。如 @RequestMapping(value = “toUser”,produces = “application/json”)。
除此之外,produces 属性还可以指定返回值的编码。如 @RequestMapping(value = "toUser",produces = "application/json,charset=utf-8")
,表示返回 utf-8 编码。
使用 @RequestMapping 来完成映射,具体包括 4 个方面的信息项:请求 URL、请求参数、请求方法和请求头。
如何配置静态资源? 1 2 3 4 5 6 <mvc:resources mapping ="/js/**" location ="/js/" > </mvc:resources > <mvc:resources mapping ="/css/**" location ="/css/" > </mvc:resources > <mvc:resources mapping ="/img/**" location ="/img/" > </mvc:resources > <mvc:annotation-driven />
如何构建Restful API? REST(Representational State Transfer)即表述性转移,是目前最流行的一种软件架构风格。它结构清晰、易于理解、有较好的扩展性。
Spring REST 风格可以简单理解为:使用 URL 表示资源时,每个资源都用一个独一无二的 URL 来表示,并使用 HTTP 方法表示操作,即准确描述服务器对资源的处理动作(GET、POST、PUT、DELETE),实现资源的增删改查。
GET:表示获取资源 POST:表示新建资源 PUT:表示更新资源 DELETE:表示删除资源 Spring Boot 65问 框架22问 启动依赖是什么? Spring Boot就可以指定基于功能依赖。Spring Boot通过起步依赖为项目的依赖管理提供帮助。如果应用程序是Web应用程序(功能),不需要向项目pom.xml文件中添加一堆单独的依赖,可以直接向项目中添加Web起步依赖。如果应用程序需要用到JPA持久化(功能),加入jpa起步依赖;如果需要安全功能(功能),就加入security起步依赖。添加依赖时不需要指定依赖的版本号,依赖的版本号由当前是使用的Spring Boot版本号来决定。
起步依赖就是特殊的Maven依赖,利用了传递依赖解析,把常用库聚合在一起,组成几个为特定功能而定制的依赖。Spring Boot通过起步依赖:直接引入相关起步依赖就行,我们不需要考虑支持某种功能需要什么库, 减少了依赖数量,而且不需要考虑这些库的那些版本。如果我们需要什么功能,就往项目中加入该功能的起步依赖就好了。
Actuator的作用? Actuator用于监视和管理应用程序
监控的内容:
Spring应用程序上下文中配置的Bean Spring Boot的自动配置做的决策 应用程序可用的环境变量、系统属性、配置属性和命令行参数等 应用程序里线程的当前状态 应用程序最近处理的HTTP请求的追踪情况 各种和内存使用、垃圾回收、Web请求等相关的指标 Spring Boot 配置依赖? 1 2 3 4 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-actuator</artifactId > </dependency >
如何修饰启动类? 1 2 3 4 5 6 7 8 9 10 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > <exclusions > <exclusion > <groupId > com.fasterxml.jackson.core</groupId > </exclusion > </exclusions > </dependency >
1 2 3 4 5 6 <dependency > <groupId > com.fasterxml.jackson.core</groupId > <artifactId > jackson-databind</artifactId > <version > 2.4.3</version > </dependency >
@SpringBootApplication是哪三合一? @SpringBootApplication = (默认属性)@Configuration + @EnableAutoConfiguration + @ComponentScan。
@Configuration:建一个简单的spring配置类,可以用来替代相应的xml配置文件,见词条 @Configuration和@Bean注解的作用
@EnableAutoConfiguration:能够自动配置spring的上下文,试图猜测和配置你想要的bean类,通常会自动根据你的类路径和你的bean定义自动配置
@ComponentScan:会自动扫描指定包下的全部标有@Component的类,并注册成bean,当然包括@Component下的子注解@Service,@Repository,@Controller
如何排除指定的自动配置? 1 @SpringBootApplication(exclude={RedisAutoConfiguration.class})
一个启动类能否同时作为控制器类? 能
如何自定义banner? 将banner.txt
(或banner,jpg
)放入src/main/resources
SpringBoot如何实现自动配置? 加载spring.factories
SpringBoot如何配置视图解析器? 配置文件
1 2 spring.mvc.view.prefix =/pages/ spring.mvc.view.suffix =.html
或
1 2 3 4 5 spring: mvc: view: prefix: /pages/ suffix: .html
配置类
1 2 3 4 5 6 7 8 9 10 @Configuration public class MvcConfig implements WebMvcConfigurer { @Bean public InternalResourceViewResolver configureInternalResourceViewResolver () { InternalResourceViewResolver resolver = new InternalResourceViewResolver (); resolver.setPrefix("/pages/" ); resolver.setSuffix(".html" ); return resolver; } }
如何配置端口号? 或
properties与yml的异同? properties的优先级会高于yml
yml采用树形结构,更有层次感,可读性很强;相反,properties 则更为直接
properties 的基本语法格式是“key=value”的形式;yml 的基本语法格式是“key: value”的形式,冒号后面需要加空格
静态资源默认位置在哪? classpath:/META-INF/resources/
classpath:/resources/
classpath:/static/
classpath:/public/
如何自定义静态资源的位置? 在配置文件中配置
1 2 3 4 spring.mvc.static-path-pattern =/upload/** spring.resources.static-locations =classpath:/upload/
配置类
1 2 3 4 5 6 7 @Configuration public class MvcConfig extends WebMvcConfigurerAdapter { @Override public void addResourceHandlers (ResourceHandlerRegistry registry) { registry.addResourceHandler("/**" ).addResourceLocations("/" ,"classpath:/" ); } }
有哪些常用的JSON解析器? 1)json-lib
json-lib 最早也是应用广泛的 JSON 解析工具,缺点是依赖很多的第三方包
对于复杂类型的转换,json-lib 在将 JSON 转换成 Bean 时还有缺陷,比如一个类里包含另一个类的 List 或者 Map 集合,json-lib 从 JSON 到 Bean 的转换就会出现问题。
2)开源的Jackson 开源的 Jackson 是 Spring MVC 内置的 JSON 转换工具。
但是 Jackson 对于复杂类型的 JSON 转换 Bean 会出现问题
3)Google的Gson Gson 是目前功能最全的 JSON 解析神器
Gson 完全可以将复杂类型的 JSON 到 Bean 或 Bean 到 JSON 的转换,是 JSON 解析的神器。Gson 在功能上面无可挑剔,但性能比 FastJson 有所差距。
4)阿里巴巴的FastJson FastJson 是用 Java 语言编写的高性能 JSON 处理器,由阿里巴巴公司开发。
FastJson 在复杂类型的 Bean 转换 JSON 上会出现一些问题,可能会出现引用的类型,导致 JSON 转换出错,需要制定引用。
为哪些JSON解析器提供了自动配置? Gson 、Jackson 、JSON-B
如何使用fastjson? 导入依赖
1 2 3 4 5 <dependency > <groupId > com.alibaba</groupId > <artifactId > fastjson</artifactId > <version > 1.2.15</version > </dependency >
在springMVC的配置类中配置JSON解析器为fastJSON
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 @Override public void configureMessageConverters (List<HttpMessageConverter<?>> converters) { FastJsonHttpMessageConverter converter=new FastJsonHttpMessageConverter (); converter.setDefaultCharset(Charset.forName("UTF-8" )); FastJsonConfig config=new FastJsonConfig (); config.setDateFormat("yyyy-MM-dd" ); config.setSerializerFeatures( SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullStringAsEmpty, SerializerFeature.WriteNullNumberAsZero, SerializerFeature.WriteNullListAsEmpty, SerializerFeature.DisableCircularReferenceDetect ); converter.setFastJsonConfig(config); converters.add(converter); for (HttpMessageConverter c:converters) System.out.println(c.getClass()); }
直接用。。。
如何自定义错误界面的位置? 静态
在 resource/static 目录下创建 error 目录,然后在 error 目录中创建错误展示页面。错误展示页面命名规则有如下两种:
一种是直接使用具体的响应码命名文件,比如:404.html、405.html、500.html 另一种可以使用 4xx.html、5xx.html 这样的命名
动态
在 resource/templates 目录下创建 error 目录,然后在 error 目录中创建错误展示页面。
错误界面使用的顺序如何? 优先级:
动态错误码>静态错误码>动态模糊错误码>静态模糊错误码
找到一个后便不往下寻找
如何定义局部异常handler? 1 2 3 4 5 6 7 @ExceptionHandler(value = {java.lang.ArithmeticException.class}) public ModelAndView arithmeticExceptionHandler (Exception e) { ModelAndView mv = new ModelAndView (); mv.addObject("errorMsg" ,e); mv.setViewName("error" ); return mv; }
如何定义全局异常handler? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler ({ ArithmeticException .class }) public String handleException (Exception ex, Model model ) { model.addAttribute ("msg" , "全局异常处理程序,异常消息:" +ex.getMessage ()); return "err" ; } @ExceptionHandler ({ArrayIndexOutOfBoundsException .class }) @ResponseBody public Map <String ,Object > handleException2 (Exception e ) { Map <String ,Object > map=new HashMap <>(); map.put ("status" , 500 ); map.put ("msg" , "数组索引出界,索引: " +e.getMessage ()); map.put ("reason" , "索引值超出数组长度" ); return map; } }
如何使用RestController? 如果在类上加上@RestController,该类中的所有SpringMVCUrl接口映射都是返回json格式
1 2 3 4 @RestController public class hello { }
Thymeleaf 11问 Thymeleaf如何使用变量表达式页面获取不同范围的属性? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 变量表达式${.....}<p > user1属性值: <span th:text ="${user1.id}" > </span > | <span th:text ="${user1.password}" > </span > | <span th:text ="${user1.gender}" > </span > </p > <p > user2属性值: <span th:text ="${session.user2.id}" > </span > | <span th:text ="${session.user2.password}" > </span > | <span th:text ="${session.user2.gender}" > </span > </p >
Thymeleaf的五种表达式? 变量表达式${…..} 选择变量表达式*{…..}选择变量表达式主要是为了简化书写 th:object属性用于绑定一个对象,这样在当前元素(p元素)内可以直接使用该对象的属性 选择变量表达式用于使用外围绑定的对象的属性,以简化书写 消息表达式#{…..}消息表达式用于显示消息,主要是来自属性文件的属性,可用于实现国际化等功能 {属性名}来显示来自属性文件的一个消息 URL链接变量表达式@{…..} 片段(fragment)表达式~{…..} 如何使用选择变量表达式? 1 2 3 4 5 6 <p th:object ="${user1}" > user1属性值: <span th:text ="*{id}" > </span > | <span th:text ="*{password}" > </span > | <span th:text ="*{gender}" > </span > </p >
链接表达式的四种写法? 1 2 3 4 5 6 7 8 9 10 11 12 <div class ="content" > <a th:href ="@{https://www.baidu.com}" class ="btn btn-sm btn-danger" > 测试1-绝对路径</a > <a th:href ="@{static/img/lxh01.gif}" class ="btn btn-sm btn-warning" > 测试2-页面/请求相对路径</a > <a th:href ="@{/static/img/lxh02.gif}" class ="btn btn-sm btn-success" > 测试3-上下文相对路径</a > <a th:href ="@{~/static/img/lxh03.gif}" class ="btn btn-sm btn-primary" > 测试4-服务器相对路径</a > <a th:href ="@{//static/img/lxh04.gif}" class ="btn btn-sm btn-info" > 测试5-协议相对路径</a > </div >
怎么定义和引用片段? 定义
1 2 3 4 5 <div th:fragment ="f1" id ="frag1" class ="bg-primary padding10 margin10" > 这是模板片段1内容~~~~~~~~~~~~~~~~~~~<br > 这是模板片段1内容~~~~~~~~~~~~~~~~~~~<br > 这是模板片段1内容~~~~~~~~~~~~~~~~~~~<br > </div >
引用
1 2 3 4 5 6 7 8 9 10 11 12 13 <div class ="content" > <div id ="div1" th:insert ="~{footer::f1}" > </div > <div id ="div2" th:replace ="~{footer::f1}" > </div > <div id ="div3" th:insert ="~{footer::#frag2}" > </div > <div id ="div4" th:insert ="~{footer}" > </div > <div id ="div5" th:insert ="~{::frag3}" > </div > <div id ="div5" th:insert ="~{this::#fragment3}" > </div > </div >
哪些字面标记不合法? 字面标记值类似文本字面值: 区别是不使用单引号括起来值, 只能允许字母、数字、下划线、中划线、点号、中括号, 不能包含逗号、空格以及其他特殊字符
1 2 3 4 5 6 7 8 字面标记:<span th:text ="Anna" > </span > <br > 字面标记:<span th:text ="Annabelle_Lee" > </span > <br > 字面标记:<span th:text ="www.baidu.com" > </span > <br > 字面标记:<span th:text ="a-b_c.d" > </span > <br >
th:*属性的作用? th:* 修改单个属性的值
1 2 3 4 5 6 7 8 9 10 11 <div class ="content" > <p > <img th:src ="'static/img/'+${user5.img}" th:title ="${user5.id}" src ="static/img/lxh01.gif" title ="小胖" width ="60" height ="60" > <img th:src ="@{'/static/img/'+${user5.img}}" th:title ="${user5.id}" src ="static/img/lxh01.gif" title ="小胖" width ="60" height ="60" > </p > </div >
th:attr 修改一个标签多个属性的值
1 2 3 4 5 6 7 <div class ="content" > <p > <img th:attr ="src=@{'/static/img/'+${user5.img}},title=${user5.id}" src ="static/img/lxh01.gif" title ="小胖" width ="60" height ="60" > </p > </div >
th:object 绑定一个对象,方便在子标记中使用选择变量表达式
1 2 3 4 5 6 7 8 9 <div class ="content" > <p th:object ="${user5}" > user5属性值: <span th:text ="*{id}" > </span > | <span th:text ="*{password}" > </span > | <span th:text ="*{gender}" > </span > | <span th:text ="*{img}" > </span > </p > </div >
th:if 判断一个条件,条件成立,显示标记内容
1 2 3 <div class ="content" > <p th:if ="${age}>=18" > 恭喜你,成为大人了!!!</p > </div >
th:switch+th:case 类似switch-case结构作用的属性
1 2 3 4 5 6 7 8 9 10 <div class ="content" > <div th:switch ="${type}" > <p th:case ="1" > 冰箱</p > <p th:case ="2" > 空调</p > <p th:case ="3" > 电视</p > <p th:case ="*" > 其他</p > </div > </div >
th:each 类似foreach循环
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 <div class ="content" > <table class ="table table-striped table-hover text-center" > <tr > <th > 学号</th > <th > 姓名</th > <th > 性别</th > </tr > <tr th:each ="s:${studentList}" > <td th:text ="${s.sid}" > </td > <td data-th-text ="${s.sname}" > </td > <td > [[${s.sgender}]]</td > </tr > </table > <div th:each ="s,stat:${studentList}" th:class ="${stat.odd}?'bg-danger':'bg-success'" > [[${s.sid}]] | [[${s.sname}]] | [[${stat.index}]] | [[${stat.count}]] | [[${stat.size}]] | [[${stat.first}]] | [[${stat.last}]] | [[${stat.odd}]] | [[${stat.even}]] | </div > <hr > <div th:each ="entry,status:${map1}" > [[${entry.key}]] | [[${entry.value}]] | [[${status.index}]] </div > </div >
th:text和th:utext
1 2 3 4 5 6 7 8 9 10 <div class ="content" > <p th:text ="${content1}" > </p > [[${content1}]] <p th:utext ="${content2}" > </p > [(${content2})]</div >
th:with 用于定义局部变量
1 2 3 4 5 6 7 8 9 <div th:with ="firstStudent=${studentList[0]}" > [[${firstStudent.sid}]] | [[${firstStudent.sname}]] | [[${firstStudent.sgender}]]</div > <div th:with ="a=10,b=20,c=30" > [[${a+b+c}]]</div >
th:inline 启用和禁用内联表达式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <div th:inline ="none" > [[1+2+3]] <br > [(1+2+3)]</div > <div > <script th:inline ="javascript" > document .write ([[${user5.id }]]); document .write ("<br>" ); document .write ([[${age}]]); </script > </div > <div > <style th:text ="css" > .bg-red { color : [[${color }]]; } </style > <p class ="bg-red" > 测试样式</p > </div >
Thymeleaf的名称空间? Thymeleaf提供一些名称空间,用于获取对应的信息。每个名称空间都对应一个Map集合,存储了对应的属性、参数或其他信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <div class ="content" > <p th:text ="${num1}" > </p > <p th:text ="${num2}" > </p > <p th:text ="${session.num3}" > </p > <p th:text ="${application.num4}" > </p > <p th:text ="${param.name}" > </p > <p th:text ="${param.hobbies}" > </p > <p th:text ="${param.hobbies[0]}" > </p > </div >
有哪些基本对象? Thymeleaf 中常用的内置基本对象如下:
ctx :上下文对象 vars :上下文变量 locale:上下文的语言环境 request:HttpServletRequest 对象(仅在 Web 应用中可用) response:HttpServletResponse 对象(仅在 Web 应用中可用) session:HttpSession 对象(仅在 Web 应用中可用) servletContext:ServletContext 对象(仅在 Web 应用中可用) 表达式工具对象如何使用? numbers:数字工具对象 1 2 3 4 5 formatDecimal()方法: 用于格式化小数数值<div class ="content" > <p th:text ="${#numbers.formatDecimal(num1,1,3)}" > </p > </div >
formatCurrency()方法:用于格式化金额,会加货币符号
1 <p th:text ="${#numbers.formatCurrency(num1)}" > </p >
sequence()方法: 用于产生一个整数序列/数组, 可以通过产生一个整数序列实现普通循环,如打印分页的页码
1 2 3 4 5 <span th:each ="i:${#numbers.sequence(1,10)}" > | <a th:href ="'findByPageNo?pageNo='+${i}" > [[${i}]]</a > |</span >
strings:字符串工具对象 1 2 3 4 5 6 7 8 9 10 11 <div class ="content" > <p th:text ="${#strings.isEmpty('')}" > </p > <p th:text ="${#strings.isEmpty('anna')}" > </p > <p th:text ="${#strings.length(bookName)}" > </p > <p th:text ="${#strings.substring(bookName,0,5)}" > </p > <p th:text ="${#strings.contains(bookName,'kite')}" > </p > </div >
dates:日期工具对象 1 2 3 4 5 6 7 8 9 10 11 <p th:text ="${#dates.format(now)}" > </p > <p th:text ="${#dates.format(now,'yyyy-MM-dd HH:mm:ss D E')}" > </p > <p th:text ="${#dates.year(now)}" > </p > <p th:text ="${#dates.month(now)}" > </p > <p th:text ="${#dates.day(now)}" > </p > <p th:text ="${#dates.monthName(now)}" > </p > <p th:text ="${#dates.dayOfWeek(now)}" > </p > <p th:text ="${#dates.hour(now)}" > </p >
lists/sets:List/Set 集合工具对象 1 2 3 4 5 6 7 <div class ="content" > <span th:each ="name:${#lists.sort(nameList)}" > [[${name}]] | </span > <p th:text ="${#lists.sort(scoreList)}" > </p > </div >
aggregates 1 2 3 4 5 <div class ="content" > <p th:text ="${#aggregates.avg(scoreList)}" > </p > <p th:text ="${#aggregates.sum(scoreList)}" > </p > </div >
maps:Map 集合工具对象 常用的方法有:size、isEmpty、containsKey 和 containsValue 等
Spring Boot JPA 13问 SpringBoot支持的三种数据源是什么? HikariCP:默认内置数据源对象
Tomcat提供DataSource:HikariCP不可用的情况下,在web环境中,将tomcat服务器配置的数据源对象。
Commons DBCP:HikariCP不可用,tomcat数据源也不可用,将使用dbcp数据源。
如何配置数据源? 导入依赖项
1 2 3 4 5 6 7 8 9 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-data-jpa</artifactId > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <scope > runtime</scope > </dependency >
1 2 3 4 5 6 7 8 9 10 spring: datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/blog?useUnicode=true&characterEncoding=utf-8 username: root password: root jpa: hibernate: ddl-auto: update show-sql: true
SpringDataJPA是什么? spring data jpa是spring提供的一套简化JPA开发的框架,按照约定好的【方法命名规则】写dao层接口,就可以在不写接口实现的情况下,实现对数据库的访问和操作。同时提供了很多除了CRUD之外的功能,如分页、排序、复杂查询等等。
SpringData JPA 需不需要JPA提供程序? 需要
Spring Data JPA 可以理解为 JPA 规范的再次封装抽象,底层还是使用了 Hibernate 的 JPA 技术实现。
JPA个各个属性都有什么作用? 1 2 3 4 5 6 7 8 spring.jpa.show-sql =true spring.jpa.properties.hibernate.format_sql =true spring.jpa.properties.hibernate.dialect =org.hibernate.dialect.MySQL57InnoDBDialect spring.jpa.hibernate.ddl-auto =update
ddl-auto的有效值有:
create: 每次加载hibernate时,先删除已存在的数据库表结构再重新生成 create-drop:每次加载hibernate时,先删除已存在的数据库表结构再重新生成,并且当sessionFactory关闭时自动删除生成的数据库表结构: update: 只在第一次加载hibernate时自动生成数据库表结构,以后再次加载hibernate时根据 model类自动更新表结构 validate:每次加载hibermate时,验证数据库表结构,仅仅和数据库中的表进行比较,不会 创建新表,但是会插入新值 none:禁用DDL操作 有哪些常用的注解? @Entity定义对象将会成为被JPA管理的实体,将映射到指定的数据库表。 @Table指定数据库的表名。 @Id定义属性为数据库的主键,一个实体里面必须有一个。 @IdClass利用外部类的联合主键。 @GeneratedValue为主键生成策略 @Basic表示属性是到数据库表的字段的映射。如果实体的字段上没有任何注解,默认即为@Basic。 @Transient表示该属性并非一个到数据库表的字段的映射,表示非持久化属性,与@Basic作用相反。JPA映射数据库的时候忽略它。 @Column定义该属性对应数据库中的列名。 @Temporal用来设置Date类型的属性映射到对应精度的字段。 @Lob 将属性映射成数据库支持的大对象类型,支持以下两种数据库类型的字段。 关联关系注解
@JoinColumn定义外键关联的字段名称 @OneToOne关联关系 @OneToMany与@ManyToOne可以相对存在,也可只存在一方。 @ManyToMany表示多对多,和@OneToOne、@ManyToOne一样也有单向、双向之分。单向双向和注解没有关系,只看实体类之间是否相互引用。 Repository接口和他的派生类型? Repository : 是 spring Data 的一个核心接口,它不提供任何方法,开发者需要在自己定义的接口中声明需要的方法 仅仅是一个标识,表明任何继承它的均为仓库接口类,方便Spring自动扫描识别
CrudRepository : 继承 Repository,实现了一组 CRUD 相关的方法
PagingAndSortingRepository : 继承 CrudRepository,实现了一组分页排序相关的方法
JpaRepository : 继承 PagingAndSortingRepository,实现一组 JPA 规范相关的方法
如何构建简单的条件查询? 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 List<Student> findByUserDepUuid (String uuid) ; List<Student> findBySbatchAndSgender (String batchName, String gender) ; List<Student> findBySidOrSname (String id, String name) ; List<Student> findBySidBetween (String start, String end) ; List<Student> findBySidLessThan (String id) ; List<Student> findBySidLessThanEqual (String id) ; List<Student> findBySidGreaterThan (String id) ; List<Student> findBySidGreaterThanEqual (String id) ; List<Student> findBySbatchNull () ; List<Student> findBySidLike (String id) ; List<Student> findBySnameLike (String name) ; List<Student> findBySnameEndingWith (String name) ;
1 2 3 4 5 6 7 8 9 10 public Product get (Long id) { return repo.findById(id).get(); }@Override public List<Student> getStudentListByUuid (String Uuid) { return studentRepository.findByUuid(Uuid); }
如何使用@Query查询? 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 @Query("select emp from Employee emp where id=(select max(id) from Employee)") Employee query1 () ;@Query("select emp from Employee emp where gender=?1 and dept.deptId=?2") List<Employee> query2 (String gender, Integer deptId) ;@Query("select emp from Employee emp where gender=:gen and dept.deptId=:did") List<Employee> query3 (@Param("gen") String gender, @Param("did") Integer deptId) ;@Query("select emp from Employee emp where name like %?1% and gender=?2") List<Employee> query4 (String name, String gender) ;@Query("select emp from Employee emp where name like %:name% and gender=:gender") List<Employee> query5 (@Param("name") String name, @Param("gender") String gender) ;@Query(value = "select * from emp", nativeQuery = true) List<Employee> query6 () ;@Query("select e.id,e.name,e.gender,d.deptId,d.deptName from Employee e, Department d where e.dept.deptId=d.deptId") List<Object[]> query7();
如何进行增删改? 直接调用JPA给定的 CRUD 方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Override public void addStudent (Student student) { studentRepository.save(student); }@Override public void updateStudent (Student student) { studentRepository.save(student); }@Override public void deleteStudent (String id) { studentRepository.deleteById(id); }
或者在repository层中定义Query
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @Modifying @Query("update Employee set name=:name where id=:id") void update1 (@Param("id") Integer id, @Param("name") String name) ;@Modifying @Query(value = "insert into emp(name,gender,dept_id) values(:name,:gender,:deptId)", nativeQuery = true) void insert (@Param("name") String name, @Param("gender") String gender, @Param("deptId") Integer deptId) ;@Modifying @Query("delete Employee where id=?1") void delete (Integer id) ;
如何声明事务? 1 2 3 4 5 @Transactional(propagation=Propagation.SUPPORTS, readOnly=true) public List<PayInfo> findAll () { return payInfoDao.findAll(); }
属性 类型 描述 value String 可选的限定描述符,指定使用的事务管理器 propagation enum: Propagation 可选的事务传播行为设置 isolation enum: Isolation 可选的事务隔离级别设置 readOnly boolean 读写或只读事务,默认读写 timeout int (in seconds granularity) 事务超时时间设置 rollbackFor Class对象数组,必须继承自Throwable 导致事务回滚的异常类数组 rollbackForClassName 类名数组,必须继承自Throwable 导致事务回滚的异常类名字数组 noRollbackFor Class对象数组,必须继承自Throwable 不会导致事务回滚的异常类数组 noRollbackForClassName 类名数组,必须继承自Throwable 不会导致事务回滚的异常类名字数组
如何配置mapper映射文件的位置? 在配置文件中
1 mybatis.mapper-locations =classpath:com/qdu/mapper/**/*.xml
如何开启对mapper包的扫描? 在启动类中
1 @MapperScan("com.qdu.mapper")
消息传递 10问 消息传递的概念? 消息传递是一个或多个实体之间进行通信的一-种方式,它无处不在。自计算机发明以来,以一种或 另一种形式进行的计算机消息传递就已经存在。它被定义为硬件和/或软件组件或应用程序之间的通 信方法。总会有一个发送者和一个或多个接收者。消息传递可以是同步和异步,发布/订阅, RPC 基于企业的消息传递,ESB (企业服务总线),MOM (面向消息的中间件)等等。
JMS的概念? JMS即Java消息服务(Java Message Service)应用程序接口,是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。Java消息服务是一个与具体平台无关的API,绝大多数MOM提供商都对JMS提供支持。
点对点模型有什么特点? 一个消息由一个消息生产者(producer) 传送给一个消息使用者(consumer) 。 消息由生产者发送到队列(Queue) 目的地,然后传送给在该队列上注册了的消息使用者之一 。 任意多数量的消息生产者都可以发送消息同一个队列,每条消息都可以确保被传送成功,且每条消息仅由一个消息使用者收到和使用 。 如果没有消息使用者注册接受队列中的消息,则队列保留该消息 ,直到有使用者读取该消息,一旦读取,该消息便不在队列中,不可再有其他使用者读取。 发布订阅模型的特点? 一个消息由一个消息生产者(Producer/Publisher) 传送给任意数量的消息使用者(Consumer/Subscriber) 。 消息由生产者发送到主题(Topic) 目的地, 然后由订阅了该主题的活跃消息使用者读取和使用 。 任意数量的消息生产者可以发送消息到主题 目的地,每条消息 传送给任意数量订阅了该主题的消息使用者 。 如果没有订阅该主题的消息使用者,则Topic目的地不会保留该消息(除非有非活跃使用者进行了持久性订阅),后续订阅该主题的消息使用者也不会再收到使用者之前发的消息。 一个持久性订阅表示注册了该主题的使用者可以在生产者发送消息的时候处于非活跃状态,这样,使用者可以在变成活跃状态时收到之前发送的消息。 ActiveMQ是什么? ActiveMQ是一种开源的基于JMS(Java Message Servie)规范的一种消息中间件的实现,ActiveMQ的设计目标是提供标准的、面向消息的、能够跨越多语言和多系统的应用集成消息通信中间件。
它为企业应用中消息传递提供高可用、出色性能、可扩展、稳定和安全保障。
ActiveMQ实现JMS规范并在此之上提供大量额外的特性。ActiveMQ支持队列和订阅两种模式的消息发送。
如何启动ActiveMQ? 1 2 cd <activeMQ_dir>/bin ./activemq start
JMS创建什么链接实例? javax.jms.Connection
(由于使用SpringBoot,此处不再赘述)
如何配置ActiveMQ? 首先配置properties文件
1 2 3 4 5 6 7 8 9 10 11 12 spring.activemq.broker-url =tcp://localhost:61616 spring.activemq.user =admin spring.activemq.password =admin spring.activemq.in-memory =false spring.activemq.packages.trust-all =true spring.activemq.pool.enabled =false
然后配置activeMQ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 @Configuration @EnableJms public class ActiveMQConfig { @Bean public Queue queue () { return new ActiveMQQueue ("springboot.queue" ) ; } @Bean public JmsListenerContainerFactory jmsTopicListenerContainerFactory (ConnectionFactory connectionFactory) { DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory (); factory.setConnectionFactory(connectionFactory); factory.setPubSubDomain(true ); return factory; } @Bean public Topic topic () { return new ActiveMQTopic ("springboot.topic" ) ; } }
或者在properties中配置
1 2 # 使用点对点模型 spring.jms.pub-sub-domain=false
配置文件的其他配置:
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 spring.activemq.packages.trust-all =spring.activemq.packages.trusted =spring.activemq.pool.block-if-full =true spring.activemq.pool.block-if-full-timeout =-1ms spring.activemq.pool.create-connection-on-startup =true spring.activemq.pool.enabled =false spring.activemq.pool.expiry-timeout =0ms spring.activemq.pool.idle-timeout =30s spring.activemq.pool.max-connections =1 spring.activemq.pool.maximum-active-session-per-connection =500 spring.activemq.pool.reconnect-on-exception =true spring.activemq.pool.time-between-expiration-check =-1ms spring.activemq.pool.use-anonymous-producers =true
@JMSListener有什么用? 1 2 3 4 5 6 @JmsListener(destination="queue2") public void receiveMsg1 (String msg) { System.out.println("监听端点1收到消息,消息内容:" +msg); }
如何使用发布订阅模型? 1 2 spring.jms.pub-sub-domain =true
测试 9问 单元测试与集成测试? 见软件工程第十一章单元测试与集成测试部分
Junit5的三个组件是什么? JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
JUnit Platform: 是在JVM上启动测试框架的基础,不仅支持Junit自制的测试引擎,其他测试引擎也都可以接入。 JUnit Jupiter: 提供了JUnit5的新的编程模型,是JUnit5新特性的核心。内部包含了一个测试引擎,用于在Junit Platform上运行。 JUnit Vintage: 由于JUint已经发展多年,为了照顾老的项目,其提供了兼容JUnit4.x,Junit3.x的测试引擎。 Junit的常用注解? @Test :表示方法是测试方法
1 2 3 @Test void contextLoads () { }
@DisplayName :为测试类或者测试方法设置展示名称
1 2 3 4 5 @DisplayName("测试displayname注解") @Test void testDisplayName () { System.out.println(1 ); }
@BeforeEach:表示在每个单元测试之前执行
@AfterEach:表示在每个单元测试之后执行
@BeforeAll:表示在所有单元测试之前执行
@AfterAll:表示在所有单元测试之后执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @BeforeEach void testBeforeEach () { System.out.println("测试就要开始。。。" ); } @AfterEach void testAfterEach () { System.out.println("测试就要结束。。。" ); } @BeforeAll static void testBeforeAll () { System.out.println("所有测试就要开始。。。" ); } @AfterAll static void testAfterAll () { System.out.println("所有测试已经结束。。。" ); }
@Disabled :表示测试类或测试方法不执行
1 2 3 4 5 6 @Disabled @Test void test2 () { System.out.println(2 ); System.out.println(jdbcTemplate.getClass()); }
@Timeout :表示测试方法运行如果超过了指定时间将会返回错误
1 2 3 4 5 @Test @Timeout(value = 500, unit = TimeUnit.MILLISECONDS) void testTimeOut () throws InterruptedException { Thread.sleep(520 ); }
@RepeatedTest :表示方法可重复执行
1 2 3 4 5 6 7 @RepeatedTest(5) @DisplayName("测试3") @Test void test3 () { System.out.println(3 ); System.out.println(jdbcTemplate.getClass()); }
@ParameterizedTest :表示方法是参数化测试
@Tag :表示单元测试类别
@ExtendWith :为测试类或测试方法提供扩展类引用
Junit的测试方法与注意事项? 就这么测。。。
注意注意就行了。。。
Test依赖包含的库有哪些?
如何测试Spring Boot程序? @SpringBootTest注解:添加在需要依赖spring boot框架的测试类上, 不然不能使用Spring boot的相关开发功能 @Test注解:添加在测试方法上
1 2 3 4 5 6 @SpringBootTest class Boot05WebAdminApplicationTests { @Test void contextLoads () { } }
MockMvc是什么? MockMvc实现了对Http请求的模拟,能够直接使用网络的形式,转换到Controller的调用,这样可以使得测试速度快、不依赖网络环境,而且提供了一套验证的工具,这样可以使得请求的验证统一而且很方便。
@WebMvcTest有什么用? 1 2 @WebMvcTest(controllers= {HelloController.class})
如果使用@SpringBootTest来修饰一个测试类, 则会加载所有配置,并注册相关的bean成为spring管理的bean, 包括service组件、mapper组件、数据源等
但是如果测试只涉及部分组件,如控制器,不需要使用service或mapper等组件, 可以使用切片测试对应的注解来实施测试,这样只加载需要的配置即可
比如使用@WebMvcTest,实现对spring mvc组件的切片测试, 这样就不能注入service等组件,因为不会加载service等的配置