2018年11月份辞职后,就开始我的漫漫求职之路,终于在2019年2月份入职了.在这期间,我面试了应该差不多30加公司了.总结了每次被问到的问题.希望对大家有帮助.我是在广州工作的.这份总结我是写在word里面,拷贝过来,每一点的序号都变成了1,大家将就一下.
- hashmap底层
数据结构中有数组和链表这两个结构来存储数据。
数组存储区间是连续的,占用内存严重,故空间复杂的很大。但数组的二分查找时间复杂度小;
数组的特点是:寻址容易,插入和删除困难;
链表存储区间离散,占用内存比较宽松,故空间复杂度很小,但时间复杂度很大。
链表的特点是:寻址困难,插入和删除容易。
综合这两者的优点,摒弃缺点,哈希表就诞生了,既满足了数据查找方面的特点,占用的空间也不大。
哈希表可以说就是数组链表,底层还是数组但是这个数组每一项就是一个链表。
HashMap 是一个用于存储Key-Value 键值对的集合,每一个键值对也叫做Entry。这些个Entry 分散存储在一个数组当中,这个数组就是HashMap 的主干。
HashMap 数组每一个元素的初始值都是Null。
HashMap的构造函数
HashMap实现了Map接口,继承AbstractMap。其中Map接口定义了键映射到值的规则,而AbstractMap类提供 Map 接口的骨干实现。
HashMap提供了三个构造函数:
HashMap():构造一个具有默认初始容量 (16) 和默认加载因子 (0.75) 的空 HashMap。
HashMap(int initialCapacity):构造一个带指定初始容量和默认加载因子 (0.75) 的空 HashMap。
HashMap(int initialCapacity, float loadFactor):构造一个带指定初始容量和加载因子的空HashMap。
HashMap也可以说是一个数组链表,HashMap里面有一个非常重要的内部静态类——Entry,这个Entry非常重要,它里面包含了键key,值value,下一个节点next,以及hash值,Entry是HashMap非常重要的一个基础Bean,因为所有的内容都存在Entry里面,HashMap的本质可以理解为 Entry[ ] 数组。
HashMap的遍历
//第三种:推荐,尤其是容量大时
System.out.println("通过Map.entrySet遍历key和value");
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}
使用HashMap的匿名内部类Entry遍历比使用keySet()效率要高很多,使用forEach循环时要注意不要在循环的过程中改变键值对的任何一方的值,否则出现哈希表的值没有随着键值的改变而改变,到时候在删除的时候会出现问题。 此外,entrySet比keySet快些。对于keySet其实是遍历了2次,一次是转为iterator,一次就从hashmap中取出key所对于的value。而entrySet只是遍历了第一次,他把key和value都放到了entry中,所以就快了。
Put 方法的原理
比如调用 hashMap.put(“apple”, 0) ,插入一个Key为“apple”的元素。这时候我们需要利用一个哈希函数来确定Entry的插入位置(index): index = Hash("apple")
但是,因为HashMap的长度是有限的,当插入的Entry越来越多时,再完美的Hash函数也难免会出现index冲突的情况。
我们可以利用链表来解决。
HashMap数组的每一个元素不止是一个Entry对象,也是一个链表的头节点。每一个Entry对象通过Next指针指向它的下一个Entry节点。当新来的Entry映射到冲突的数组位置时,只需要插入到对应的链表即可:
新来的Entry节点插入链表时,使用的是“头插法。
Get方法的原理
首先会把输入的Key做一次Hash映射,得到对应的index:
index = Hash(“apple”)
由于刚才所说的Hash冲突,同一个位置有可能匹配到多个Entry,这时候就需要顺着对应链表的头节点,一个一个向下来查找。假设我们要查找的Key是“apple”:
第一步,我们查看的是头节点Entry6,Entry6的Key是banana,显然不是我们要找的结果。
第二步,我们查看的是Next节点Entry1,Entry1的Key是apple,正是我们要找的结果。
之所以把Entry6放在头节点,是因为HashMap的发明者认为,后插入的Entry被查找的可能性更大。
HashMap的初始长度
初始长度为16,且每次自动扩容或者手动初始化的时候必须是2的幂。
如何进行位运算呢?有如下的公式(Length是HashMap的长度):
之前说过,从Key映射到HashMap数组的对应位置,会用到一个Hash函数:
index = Hash(“apple”)
如何实现一个尽量均匀分布的Hash函数呢?我们通过利用Key的HashCode值来做某种运算。
index = HashCode(Key) & (Length - 1)
下面我们以值为“book”的Key来演示整个过程:
- 计算book的hashcode,结果为十进制的3029737,二进制的101110001110101110 1001。
- 假定HashMap长度是默认的16,计算Length-1的结果为十进制的15,二进制的1111。
- 把以上两个结果做与运算,101110001110101110 1001 & 1111 = 1001,十进制是9,所以 index=9。
可以说,Hash算法最终得到的index结果,完全取决于Key的Hashcode值的最后几位。这里的位运算其实是一种快速取模算法
hashmap的特点
1.底层实现是 链表数组,JDK 8 后又加了 红黑树;
2.实现了 Map 全部的方法
3.key 用 Set 存放,所以想做到 key 不允许重复,key 对应的类需要重写 hashCode 和 equals 方法
4. 允许空键和空值(但空键只有一个,且放在第一位
5. 元素是无序的,而且顺序会不定时改变
- MySql
Mysql的优点:简单,开源免费,小巧,速度快,可移植性高,连接性和安全性好
Mysql的缺点:不支持热备份,没有一种存储过程语言
(1)、索引是什么
索引是对数据库中一或多个列值的排序,帮助数据库高效获取数据的数据结构
假如我们用类比的方法,数据库中的索引就相当于书籍中的目录一样,当我们想找到书中的摸个知识点,我们可以直接去目录中找而不是在书中每页的找,但是这也抛出了索引的一个缺点,在对数据库修改的时候要修改索引到导致时间变多。
几个基本的索引类型: 普通索引、 唯一索引、主键索引 、全文索引
索引优点
· 加快检索速度
· 唯一索引确保每行数据的唯一性
· 在使用索引的过程可以优化隐藏器,提高系统性能
索引缺点
· 插入删除 修改 维护速度下降
· 占用物理和数据空间
(2)、事务
事务的作用
事务(Transaction)是并发控制的基本单位。事务就是一系列的操作,这些操作要么都执行,要么都不执行。
事务具有以下4个基本特征
· Atomic(原子性) 事务中的一系列的操作要么都完成,要么全部失败
· Consistency(一致性) 一个成功的事务应该讲数据写入的到数据库,否则就要回滚到最初的状态
· Isolation(隔离性) 并发访问和修改的独立
· Durability(持久性) 事务结束应该讲事务的处理结构存储起来
事务的语句
· 开始事物:BEGIN TRANSACTION
· 提交事物:COMMIT TRANSACTION
· 回滚事务:ROLLBACK TRANSACTION
(3)、数据库中的乐观锁和悲观锁
· 悲观锁 假定会发生并发冲突,屏蔽任何违反数据完整的操作
· 乐观锁 假定不会发生冲突,只有在提交操作时检查是否违反数据的完整性
(4)、drop、delete、 truncate的区别
delete和truncate只删除表的数据不删除表的结构
· 速度 drop > truncate > delete
· 想删除部分数据时, delete 删除时要带上where语句
· 保留表而想删除所有的数据时用truncate
(5)、视图的作用,视图可以更改么?
视图是虚拟的表,与包含数据的表不一样,视图只包含使用时动态检索数据的查询;不包含任何列或数据。使用视图可以简化复杂的sql操作,隐藏具体的细节,保护数据;视图创建后,可以使用与表相同的方式利用它们。
视图不能被索引,也不能有关联的触发器或默认值,如果视图本身内有order by 则对视图再次order by将被覆盖。
对于某些视图比如未使用联结子查询分组聚集函数Distinct Union等,是可以对其更新的,对视图的更新将对基表进行更新;但是视图主要用于简化检索,保护数据,并不用于更新,而且大部分视图都不可以更新。
(6)、应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:
select id from t where num=10 or num=20
可以这样查询:
select id from t where num=10
union all
select id from t where num=20
(7)、下面的查询也将导致全表扫描:
select id from t where name like '%abc%'
若要提高效率,可以考虑全文检索。
(8)、in 和 not in 也要慎用,否则会导致全表扫描,如:
select id from t where num in(1,2,3)
对于连续的数值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3
(9)、不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。
(10)、很多时候用 exists 代替 in 是一个好的选择
(11)、索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。
(12)、尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。
(13)、在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果数据量不大,为了缓和系统表的资源,应先create table,然后insert。
- json
JSON(JavaScript Object Notation)一种轻量级的数据交互格式
类似于一种数据封装,可以想象为java中student封装类
它是基于JavaScript的一个子集。数据格式简单, 易于读写, 占用带宽小
JSON的数值可以是数字、字符串、布尔值、数组或者对象、null
什么是JSON和XML
JSON:JavaScript Object Notation 【JavaScript 对象表示法】.
XML:extensiable markup language 被称作可扩展标记语言
JSON和XML都是数据交换语言,完全独立于任何程序语言的文本格式。
XML文件格式复杂,比较占宽带,服务器端与客户端解析xml话费较多的资源和时间.
JSON解析方式(阿里巴巴fastjson、谷歌gson,jackJson)
XML解析方式(dom、sax、pul)
XML和JSON优缺点
XML的优点
- A.格式统一,符合标准;
- B.容易与其他系统进行远程交互,数据共享比较方便
XML的缺点
- A.XML文件庞大,文件格式复杂,传输占带宽;
- B.服务器端和客户端都需要花费大量代码来解析XML,导致服务器端和客户端代码变得异常复杂且不易维护;
- C.客户端不同浏览器之间解析XML的方式不一致,需要重复编写很多代码;
- D.服务器端和客户端解析XML花费较多的资源和时间。
JSON的优点
- A.数据格式比较简单,易于读写,格式都是压缩的,占用带宽小;
- B.易于解析,客户端JavaScript可以简单的通过eval_r()进行JSON数据的读取;
- C.支持多种语言,包括ActionScript, C, C#, ColdFusion, Java, JavaScript, Perl, PHP, Python, Ruby等服务器端语言,便于服务器端的解析;
- D.因为JSON格式能直接为服务器端代码使用,大大简化了服务器端和客户端的代码开发量,且完成任务不变,并且易于维护
JSON的缺点
- A.没有XML格式这么推广的深入人心和喜用广泛,没有XML那么通用性;
- B.JSON片段的创建和验证过程比一般的XML稍显复杂。
- mvc的理解
MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。
Model(模型):数据模型,提供要展示的数据,因此包含数据和行为,主要提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务。主要使用的技术:数据模型:实体类(JavaBean),数据访问:JDBC,Hibernate等。
View(视图):负责进行模型的展示,一般就是我们见到的用户界面,比如JSP,Html等
Controller(控制器):接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图负责展示。主要使用的技术:servlet,Struts中的Action类等。
MVC是一个框架模式,它强制性的使应用程序的输入、处理和输出分开。使用MVC应用程序被分成三个核心部件:模型、视图、控制器。它们各自处理自己的任务。最典型的MVC就是JSP + servlet + javabean的模式。
JSP是一种动态网页技术。它把HTML页面中加入Java脚本,以及JSP标签构成JSP文件。当浏览器请求某个JSP页面时,Tomcat会把JSP页面翻译为Java文件。
- springmvc的理解
SpringMvc是基于过滤器对servlet进行了封装的一个框架,我们使用的时候就是在web.xml文件中配置DispatcherServlet类;SpringMvc工作时主要是通过DispatcherServlet管理接收到的请求并进行处理。
具体执行流程如下:
SpringMVC运行原理
- 客户端请求提交到DispatcherServlet
- 由DispatcherServlet控制器查询HandlerMapping,找到并分发到指定的Controller中。
- Controller调用业务逻辑处理后,返回ModelAndView
- DispatcherServlet查询一个或多个ViewResoler视图解析器,找到ModelAndView指定的视图
- 视图负责将结果显示到客户端
SpringMVC的优点:
清晰的角色划分
强大的JavaBean配置
可适配,非侵入
可复用的业务代码
可定制的绑定和验证
灵活的model转换:在Springweb框架中,使用基于Map的键/值对来达到轻易的与各种视图技术集成。
简单而强大的JSP标签库
JSP表单标签库:在Spring2.0中引入的表单标签库,使用在JSP编写表单更加容易。
常用的jsp标签
<form:input>、<form:password>、<form:hidden>、<form:textarea>、<form:checkbox>、<form:select>
- spring的核心模块
(1)、Spring Core【核心容器】:核心容器提供了Spring的基本功能。核心容器的核心功能是用IOC容器来管理类的依赖关系。
(2)、Spring AOP【面向切面】:Spring的AOP模块提供了面向切面编程的支持。SpringAOP采用的是纯Java实现,采用基于代理的AOP实现方案,AOP代理由IOC容器负责生成、管理,依赖关系也一并由IOC容器管理。
(3)、Spring ORM【对象实体映射】:提供了与多个第三方持久层框架的良好整合。
(4)、Spring DAO【持久层模块】: Spring进一步简化DAO开发步骤,能以一致的方式使用数据库访问技术,用统一的方式调用事务管理,避免具体的实现侵入业务逻辑层的代码中。
(5)、Spring Context【应用上下文】:它是一个配置文件,为Spring提供上下文信息,提供了框架式的对象访问方法。
(6)、Spring Web【Web模块】:提供了基础的针对Web开发的集成特性。
(7)、Spring MVC【MVC模块】:提供了Web应用的MVC实现。Spring的MVC框架并不是仅仅提供一种传统的实现,它提供了一种清晰的分离模型。
- spring控制反转,依赖注入的理解
所有的一切都是为了松耦合
如果一个类A 的功能实现需要借助于类B,那么就称类B是类A的依赖,如果在类A的内部去实例化类B,那么两者之间会出现较高的耦合,一旦类B出现了问题,类A也需要进行改造,如果这样的情况较多,每个类之间都有很多依赖,那么就会出现牵一发而动全身的情况,程序会极难维护,并且很容易出现问题。要解决这个问题,就要把A类对B类的控制权抽离出来,交给一个第三方去做,把控制权反转给第三方,就称作控制反转(IOC Inversion Of Control)。控制反转是一种思想,是能够解决问题的一种可能的结果,而依赖注入(Dependency Injection)就是其最典型的实现方法。由第三方(我们称作IOC容器)来控制依赖,把他通过构造函数、属性或者工厂模式等方法,注入到类A内,这样就极大程度的对类A和类B进行了解耦。
依赖注入spring的注入方式:
-
-
- set注入方式
- 静态工厂注入方式
- 构造方法注入方式
- 基于注解的方式
-
- redis的用途
redis常用的五种数据类型
(1)、String(字符串)
String是简单的 key-value 键值对,value 不仅可以是 String,也可以是数字。它是Redis最基本的数据类型,一个redis中字符串value最多可以是512M。
(2)、Hash(哈希)
Redis hash 是一个键值对集合,对应Value内部实际就是一个HashMap,Hash特别适合用于存储对象。
(3)、List(列表)
Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素导列表的头部(左边)或者尾部(右边)。
(4)、Set(集合)
Redis的Set是String类型的无序集合,它的内部实现是一个 value永远为null的HashMap,实际就是通过计算hash的方式来快速排重的,这也是set能提供判断一个成员是否在集合内的原因。
(5)、zset(有序集合)
Redis zset 和 set 一样也是String类型元素的集合,且不允许重复的成员,不同的是每个元素都会关联一个double类型的分数,用来排序。
为什么使用redis?
(1)、解决应用服务器的cpu和内存压力
(2)、减少io的读操作,减轻io的压力
(3)、关系型数据库的扩展性不强,难以改变表结构
优点:
(1)、nosql数据库没有关联关系,数据结构简单,拓展表比较容易
(2)、nosql读取速度快,对较大数据处理快
适用场景:
(1)、数据高并发的读写
(2)、海量数据的读写
(3)、对扩展性要求高的数据
不适用场景:
(1)、需要事务支持
(2)、基于sql结构化查询储存,关系复杂
使用场景:
配合关系型数据库做高速缓存
换成高频次访问的数据,降低数据库io
分布式架构,做session共享
可以持久化特定数据
利用zset类型可以存储排行榜
利用list的自然时间排序存储最新n个数据
- servlet的理解
Servlet是一个作为浏览器与数据库之间的中间层,它是为了解决实现动态页面而衍生的一个java组件。也就是说Servlet就是一个程序,是什么程序呢,是运行在web服务器端的程序。
作用:
浏览器发送请求给Tomcat,Tomcat作为Servlet容器,会找到对应的Servlet并将http请求文本接收并解析,然后封装成HttpServletRequest类型的request对象。Servlet接受处理通过设置response对象,然后将response对象交给Tomcat,Tomcat就会将其变成响应文本的格式发送给浏览器。
Servlet生命周期
首先Tomcat接收到http请求后,会检查是否装载并创建了对应的Servlet,如果是,则创建一个用于封装HTTP请求消息的HttpServletRequest对象和一个代表HTTP响应消息的HttpServletResponse对象,
然后调用Servlet的service()方法,(一般我们继承了HttpServlet类后会覆写doGet()和doPoat()方法)并将请求和响应对象作为参数传递进去。如果否,装载并创建该Servlet的一个实例对象,调用Servlet实例对象的init()方法,然后执行上面同样的步骤。
Tomcat被停止或重新启动之前,Servlet引擎将卸载Servlet,并在卸载之前调用Servlet的destroy()方法。
- mybatis的优缺点\hibernate的优缺点
MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以对配置和原生Map使用简单的 XML 或注解,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
MyBatis框架的优点:
(1). 与JDBC相比,减少了50%以上的代码量。
(2). MyBatis是最简单的持久化框架,小巧并且简单易学。
(3). MyBatis相当灵活,不会对应用程序或者数据库的现有设计强加任何影响,SQL写在XML里,从程序代码中彻底分离,降低耦合度,便于统一管理和优化,并可重用。
(4). 提供XML标签,支持编写动态SQL语句。
(5). 提供映射标签,支持对象与数据库的ORM字段关系映射。
MyBatis框架的缺点:
(1). SQL语句的编写工作量较大,尤其是字段多、关联表多时,更是如此,对开发人员编写SQL语句的功底有一定要求。
(2). SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。
MyBatis框架适用场合:
MyBatis专注于SQL本身,是一个足够灵活的DAO层解决方案。
对性能的要求很高,或者需求变化较多的项目,如互联网项目,MyBatis将是不错的选择。
hibernate:
(1). 功能强大,数据库无关性好,O/R映射能力强,如果你对Hibernate相当精通,而且对Hibernate进行了适当的封装,那么你的项目整个持久层代码会相当简单,需要写的代码很少,开发速度很快。
(2). 有更好的二级缓存机制,可以使用第三方缓存。
(3). 缺点就是学习门槛不低,要精通门槛更高,而且怎么设计O/R映射,在性能和对象模型之间如何权衡取得平衡,以及怎样用好Hibernate方面需要你的经验和能力都很强才行。
- 跨域的理解
当用户对不同协议或不同端口或不同域名的资源进行访问时,就是跨域。
为什么会造成跨域
罪魁祸首:同源策略
同源定义:即同一域,即相同协议&相同端口&相同域名&相同子域名
同源策略规定:XHR对象只能访问与包含它的页面位于同一域中的资源,有利于预防一些恶意行为。
解决办法有很多,CORS、iframe、h5新特性postMessage等,而比较简单的方法就是jsonp。
JSONP,JSON with Padding的简写,这个全称对jsonp的理解还是有一定的帮助的。填充式JSON或者说是参数式JSON。JSONP的语法和JSON很像,简单来说就是在JSON外部用一个函数包裹着。JSONP基本语法如下:
callback({ "name": "kwan" , "msg": "获取成功" });
JSONP两部分组成:回调函数和里面的数据。回调函数是当响应到来时,应该在页面中调用的函数,一般是在发送过去的请求中指定。
JSONP原理:
刚才的解决依据可知,JSONP原理就是动态插入带有跨域url的<script>标签,然后调用回调函数,把我们需要的json数据作为参数传入,通过一些逻辑把数据显示在页面上。
注意了,千万不要认为用了jQuery ajax,就是通过它来实现跨域请求,其实只是因为它很好地封装了JSONP而已
用jQuery ajax原理和上面的是一样的,只不过我们不需要手动的插入script标签以及定义回调函数。jquery会自动生成一个全局函数来替换callback=?中的问号,之后获取到数据后又会自动销毁,实际上就是起一个临时代理函数的作用。
- jdk有哪些容器
数组,String,java.util下的集合容器:List,Set,Map
- java的门面
理解:医院部门和分诊台,分诊台就是门面
门面模式的优点:
● 松散耦合 门面模式松散了客户端与子系统的耦合关系,让子系统内部的模块能更容易扩展和维护。
● 简单易用 门面模式让子系统更加易用,客户端不再需要了解子系统内部的实现,也不需要跟众多子系统内部的模块进行交互,只需要跟门面类交互就可以了。
● 更好的划分访问层次 通过合理使用Facade,可以帮助我们更好地划分访问的层次。有些方法是对系统外的,有些方法是系统内部使用的。把需要暴露给外部的功能集中到门面中,这样既方便客户端使用,也很好地隐藏了内部的细节。
- Linux的常用命令
- ls命令 就是list的缩写
ls -a 列出目录所有文件,包含以.开始的隐藏文件
ls -r 反序排列
- cd命令(changeDirectory)切换当前目录至dirName
cd / 进入要目录
cd ~ 进入"家"目录
cd - 进入上一次工作路径
- pwd命令 查看当前工作目录路径
查看当前路径 pwd
查看软链接的实际路径 pwd -P
- mv命令 移动文件或修改文件名
将文件test.log重命名为test1.txt
mv test.log test1.txt
将文件log1.txt,log2.txt,log3.txt移动到根的test3目录中
mv llog1.txt log2.txt log3.txt /test3
- more命令 more会以一页一页的显示方便使用者逐页阅读,而最基本的指令就是按空白键(space)就往下一页显示,按 b 键就会往回(back)一页显示
命令参数:
+n 从笫n行开始显
-n 定义屏幕大小为n行
-c 从顶部清屏,然后显示
- head命令 head 用来显示档案的开头至标准输出中,默认head命令打印其相应文件的开头10行。
显示1.log文件中前20行 head 1.log -n 20
显示1.log文件前20字节 head -c 20 log2014.log
显示t.log最后10行 head -n -10 t.log
- which命令 在linux要查找某个文件,但不知道放在哪里了,可以使用下面的一些命令来搜索
which 查看可执行文件的位置。
whereis 查看文件的位置。
locate 配合数据库查看文件位置。
find 实际搜寻硬盘查询文件名称
- locate命令 -l num(要显示的行数)
- grep命令 文本搜索命令
命令格式:
grep [option] pattern file|dir
-f 从文件中读取关键词
-n 显示匹配内容的所在文件中行数
查找指定进程ps -ef | grep svn
- 数据库三范式
第一范式要求数据表中的每一列(每个字段)必须是不可拆分的最小单元。
第二范式要求表中的所有列,都必须依赖于主键,而不能有任何一列与主键没有关系。
第三范式要求表中的每一列只与主键直接相关而不是间接相关,表中的每一列只能依赖于主键。
· 1NF 字段是最小单元,不可再分
· 2NF 满足1NF 表中字段必须完全依赖全部主键而并非部分主键
· 3NF 满足2NF,非主键外的所有字段必须互不依赖
- 如何保证数据安全
数据加密
常见的加密算法有可逆加密算法和不可逆加密算法,可逆加密算法又分为对称加密算法和非对称加密算法。
常用对称加密算法:常见的对称加密算法有DES、3DES、AES、RC5、RC6
DES、数据加密标准,速度较快,适用于加密大量数据的场合
3DES、是基于DES,对一块数据用三个不同的密钥进行三次加密,强度更高
AES、高级加密标准,是下一代的加密算法标准,速度快,安全级别高
数据签名
相当于对传输的数据,进行一些不可逆加密算法后,如md5,生成一段签名字符串sign。
登陆操作中如果还要传输IP,地点等等数据,这些数据明显没那么重要,这时可以对全部传输数据进行签名,生成sign,将其传入后端,后端用同样算法及密钥计算比较sign,如果一致认为数据正确,直接拿到IP,地点等数据(不用解密,相对于解密各个信息,理论上所有信息计算签名要节省时间),不一致则认为被修改过,返回错误信息。
session,token机制
session(cookie)和token机制的出现是为了校验用户状态的。
Https(数字证书机制)
对于两台服务器交互,可能不用太担心,但是如果是webapp或者原生app,不法分子反编译前端代码后,就有可能拿到加密方法和加密key,怎么办呢?
在加密算法中,有一种叫做非对称加密的算法,有公钥和私钥组成,他有个特点:公钥加密的数据,只有私钥能解密;私钥加密的数据,只有公钥能解密。
https就是需要让客户端与服务器端安全地协商出一个对称加密算法。剩下的就是通信时双方使用这个对称加密算法进行加密解密。
- ssm和ssh的区别,分别适用哪些项目开发
其实就是对比struct2和springmvc的区别以及mybatis和hibernate的区别
(1)、Struct和Spring-MVC都是负责取转发的,但是两者针对request的请求上面区别很大,Struct是针对一个Action类来进行请求的,即一个Action类对应于一个请求,所以类拦截,请求的数据类共享。而Spring-MVC则是针对于方法级别的请求的,也就是一个方法对应于一个请求,属于方法拦截,请求的数据方法不共享。
(2)、Spring-MVC的配置文件相对来说较为少,容易上手,可以加快软件开发的速度,亲身体验有效。
(3)、Spring-MVC的入口是Servlet级别的而Struct的级别是Filter级别的。
- rabbitMQ的使用场景
(1)、跨系统的异步通信,所有需要异步交互的地方都可以使用消息队列。就像我们除了打电话(同步)以外,还需要发短信,发电子邮件(异步)的通讯方式。
(2)、多个应用之间的耦合,由于消息是平台无关和语言无关的,而且语义上也不再是函数调用,因此更适合作为多个应用之间的松耦合的接口。基于消息队列的耦合,不需要发送方和接收方同时在线。在企业应用集成(EAI)中,文件传输,共享数据库,消息队列,远程过程调用都可以作为集成的方法。
(3)、应用内的同步变异步,比如订单处理,就可以由前端应用将订单信息放到队列,后端应用从队列里依次获得消息处理,高峰时的大量订单可以积压在队列里慢慢处理掉。由于同步通常意味着阻塞,而大量线程的阻塞会降低计算机的性能。
(4)、消息驱动的架构(EDA),系统分解为消息队列,和消息制造者和消息消费者,一个处理流程可以根据需要拆成多个阶段(Stage),阶段之间用队列连接起来,前一个阶段处理的结果放入队列,后一个阶段从队列中获取消息继续处理。
(5)、应用需要更灵活的耦合方式,如发布订阅,比如可以指定路由规则。
(6)、跨局域网,甚至跨城市的通讯(CDN行业),比如北京机房与广州机房的应用程序的通信。
- TCP和UDP的区别及其适用场景
什么是TCP、UDP
TCP是传输控制协议,提供的是面向连接、可靠的字节流服务。
UDP是用户数据报协议,是一个简单的面向数据报的运输层协议。
区别
- TCP面向连接的运输层协议,UDP无连接
- TCP是可靠交付,UDP是尽最大努力交付
- TCP面向字节流,UDP面向报文
- TCP是点对点连接的,UDP一对一,一对多,多对多都可以
- TCP适合用于网页,邮件等,UDP适合用于视频,语音广播等
- TCP和UDP的适用场景:
- 整个数据要准确无误的传递给对方,这往往用于一些要求可靠的应用,比如HTTP、HTTPS、FTP等传输文件的协议,POP、SMTP等邮件传输的协议。
- 当对网络通讯质量要求不高的时候,要求网络通讯速度能尽量的快,比如视频、广播等,这时就可以使用UDP
- (转发)forward与(重定向)redirect的区别
forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器。浏览器根本不知道服务器发送的内容从哪里来的,所以它的地址栏还是原来的地址。
redirect是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址,所以地址栏显示的是新的URL。
forward转发页面和转发到的页面可以共享request里面的数据。redirect不能共享数据。
redirect不仅可以重定向到当前应用程序的其他资源,还可以重定向到同一个站点上的其他应用程序中的资源,甚至是使用绝对URL重定向到其他站点的资源。
forward只能在同一个Web应用程序内的资源之间转发请求。
forward是服务器内部的一种操作。
redirect是服务器通知客户端,让客户端重新发起请求。
forward一般用于用户登陆的时候根据角色转发到相应的模块。
redirect一般用于用户注销登陆时返回主页面和跳转到其它的网站等。
forward效率高。redirect效率低。
- Ajax 是什么? 如何创建一个Ajax?
ajax的全称:Asynchronous Javascript And XML。
异步传输+js+xml。
所谓异步,在这里简单地解释就是:向服务器发送请求的时候,我们不必等待结果,而是可以同时做其他的事情,等到有了结果它自己会根据设定进行后续操作,与此同时,页面是不会发生整页刷新的,提高了用户体验。
(1)创建XMLHttpRequest对象,也就是创建一个异步调用对象
(2)创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息
(3)设置响应HTTP请求状态变化的函数
(4)发送HTTP请求
(5)获取异步调用返回的数据
(6)使用JavaScript和DOM实现局部刷新
- 2019年1月16日星期三面试题
(1)、SQL去重
如果是这种情况的话用distinct是过滤不了的,这就要用到主键id的唯一性特点及group by分组example:select * from table where id in (select max(id) from table group by [去除重复的字段名列表,....])
SELECT * FROM test
WHERE id IN
(SELECT MAX(id) FROM test GROUP BY name having COUNT(*) > 1)
(2)、查询id为13的数据的下一条数据
id都不是连续的,因此意图通过id-1或者id+1是肯定行不通的,那么怎么办呢?其实也简单就是查询比id=13小的元素中的最大值,比id=13大的元素中的最小值。
select * from test where id in
(select
case
when SIGN(id-13)>0 THEN MIN(id)
when SIGN(id-13)<0 THEN MAX(id)
ELSE id
end
from test
GROUP BY SIGN(id-13)
ORDER BY SIGN(id-13)
)
ORDER BY id
--------------------------------------------------------------------------------------
select * from test where id in
(select
case
when SIGN(id-13)>0 THEN MIN(id)
when SIGN(id-13)<0 THEN MAX(id)
end
from test
where id !=13
GROUP BY SIGN(id-13)
ORDER BY SIGN(id-13)
)
ORDER BY id
(3)、用SQL实现行数据变列数据
#行转列sql CREATE TABLE StudentScores ( UserName VARCHAR(20), Sub VARCHAR(30), Score INT(3) ) insert into StudentScores(UserName, Sub, Score) values ('张三', '语文', 80), ('张三', '数学', 90), ('张三', '英语', 70), ('张三', '生物', 85), ('李四', '语文', 80), ('李四', '数学', 92), ('李四', '英语', 76), ('李四', '生物', 88), ('码农', '语文', 60), ('码农', '数学', 82), ('码农', '英语', 96), ('码农', '生物', 78);
SELECT UserName , MAX(CASE Sub WHEN '数学' THEN score ELSE 0 END ) 数学, MAX(CASE Sub WHEN '语文' THEN score ELSE 0 END ) 语文, MAX(CASE Sub WHEN '英语' THEN score ELSE 0 END ) 英语 FROM StudentScores GROUP BY UserName;
#列转行 CREATE TABLE `TEST_TB_GRADE4` ( `ID` int(10) NOT NULL AUTO_INCREMENT, `USER_NAME` varchar(20) DEFAULT NULL, `CN_SCORE` float DEFAULT NULL, `MATH_SCORE` float DEFAULT NULL, `EN_SCORE` float DEFAULT '0', PRIMARY KEY (`ID`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; insert into TEST_TB_GRADE4(USER_NAME, CN_SCORE, MATH_SCORE, EN_SCORE) values ("张三", 34, 58, 58), ("李四", 45, 87, 45), ("王五", 76, 34, 89);
select user_name, '语文' COURSE , CN_SCORE as SCORE from TEST_TB_GRADE4 union select user_name, '数学' COURSE, MATH_SCORE as SCORE from TEST_TB_GRADE4 union select user_name, '英语' COURSE, EN_SCORE as SCORE from TEST_TB_GRADE4 order by user_name,COURSE;
|
(4)、泛型<?>和<T>的区别
T 代表一种类型
?是通配符,泛指所有类型
使用<T>来声明类型持有者名称,自定义泛型类时,类持有者名称可以使用T(Type),如果是容器的元素可以使用E(Element),若键值匹配可以用K(Key)和V(Value)等,若是<?>,则是默认是允许Object及其下的子类,也就是java的所有对象了。
(5)、子父类关系中,子类构造函数可以覆盖父类构造函数吗?可以的
(6)、接口可以多继承吗?可以
(7)、Linux下载命令,远程复制命令,递归赋权
wget是Linux最常用的下载命令, 一般的使用方法是: wget + 空格 + 要下载文件的url路径
Linux下提供了scp(secure copy)命令,用于进行远程拷贝文件,功能类似cp命令,支持跨服务器,并且提供加密传输。
scp基本命令格式如下:
scp [...] src_file dst_file
chmod -R 755 文件夹名
命令 : chmod -R 755 tools_command/
解释 : -R 为递归遍历tools_command文件夹, chmod 755修改权限
(8)、多线程实现方式
1.继承Thread类,重写run方法
2.实现Runnable接口,重写run方法,实现Runnable接口的实现类的实例对象作为Thread构造函数的target
3.通过Callable和FutureTask创建线程
4.通过线程池创建线程
前面两种可以归结为一类:无返回值,原因很简单,通过重写run方法,run方式的返回值是void,所以没有办法返回结果
后面两种可以归结成一类:有返回值,通过Callable接口,就要实现call方法,这个方法的返回值是Object,所以返回的结果可以放在Object对象中
---------------------
(9)、多线程start和run的区别
用start方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码。通过调用Thread类的 start()方法来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到cpu时间片,就开始执行run()方法,这里方法 run()称为线程体,它包含了要执行的这个线程的内容,Run方法运行结束,此线程随即终止。
run()方法只是类的一个普通方法而已,如果直接调用Run方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码,这样就没有达到写线程的目的。
(10)、线程池的几个重要参数
①、corePollSize:核心线程数。在创建了线程池后,线程中没有任何线程,等到有任务到来时才创建线程去执行任务。默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中。
②、maximumPoolSize:最大线程数。表明线程中最多能够创建的线程数量。
③、keepAliveTime:空闲的线程保留的时间。
④、TimeUnit:空闲线程的保留时间单位。
⑤、wuBlockingQueue<Runnable>:阻塞队列,存储等待执行的任务。参数有ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue可选。
⑥、ThreadFactory:线程工厂,用来创建线程
⑦、RejectedExecutionHandler:队列已满,而且任务量大于最大线程的异常处理策略。
- 1月17日面试
(1)JAVA递归法反转字符串
public String reverseStr(String str){
if(str.length() <= 1){
return str;
}
return reverseStr(str.substring(1)) + str.charAt(0);
}
(2)做SQL笔试题
(3)继承关系中执行顺序
父类静态代码块
子类静态代码块
父类代码块
父类构造
子类代码块
子类构造
(4)mybatis mapper接口方法不能重载
- MySQL的连接查询
内连接 inner join on
Select * from a inner join b on a.a_id = b.b_id;
说明:组合两个表中的记录,返回关联字段相符的记录,也就是返回两个表的交集(阴影)部分。
左连接(左外连接) left join on / left outer join on
Selec * from a left join b on a.a_id = b.b_id
说明:
left join 是left outer join的简写,它的全称是左外连接,是外连接中的一种。
左(外)连接,左表(a_table)的记录将会全部表示出来,而右表(b_table)只会显示符合搜索条件的记录。右表记录不足的地方均为NULL。
右连接(右外连接) right join on / right outer join on
Select * from a right join b on a.a_id = b.b_id;
说明:
right join是right outer join的简写,它的全称是右外连接,是外连接中的一种。
与左(外)连接相反,右(外)连接,左表(a_table)只会显示符合搜索条件的记录,而右表(b_table)的记录将会全部表示出来。左表记录不足的地方均为NULL。
MySQL目前不支持全连接方式,可以用其他方式替代解决。
- Java自动装箱、拆箱
//声明一个Integer对象 |
java对于Integer与int的自动装箱与拆箱的设计,是一种模式:叫享元模式(flyweight)
为了加大对简单数字的重利用,java定义:在自动装箱时对于值从–128到127之间的值,它们被装箱为Integer对象后,会存在内存中被重用,始终只存在一个对象
而如果超过了从–128到127之间的值,被装箱后的Integer对象并不会被重用,即相当于每次装箱时都新建一个 Integer对象;
- 面向对象的理解
我们自己有手脚眼口鼻等一系列的器官。来把自己所具有的器官就可以看作我们的属性,自己是不是可以喜怒哀乐和嬉笑怒骂,这些是不是我们的行为,那么自己的具有的属性加自己有的行为就称为一个对象。
注意!!我们自己,一个个体是一个对象,因为,你是你,我是我,我们虽然有相同的,但是我们不一样,比如你比我高,我比你头发长。
接下来在进一步。我和你都是人,因为我和你有相似的东西,所以我和你都属于人类。人类,就是人的总称,也是相似对象的一种抽象。
从上面看:我和你只是人类的两个特列,但是外星人也可以用人类来称呼我们,看的出来:类的具体表现或者实例就是对象,而对象的抽象或者总概括就是类。
- IO流
字节流和字符流的区别
1)字节流操作的基本单元为字节;字符流操作的基本单元为Unicode码元。
2)字节流默认不使用缓冲区;字符流使用缓冲区。
3)字节流通常用于处理二进制数据,实际上它可以处理任意类型的数据,但它不支持直接写入或读取Unicode码元;字符流通常处理文本数据,它支持写入及读取Unicode码元。
- 某团队有 2/5 的人会写 Java 程序,有 3/4 的人会写 C++程序,这个团队里同时会写 Java 和 C++的最少有______人。
P(A∪B)=P(A)+P(B)-P(A∩B) 2/5 + 3/4 - X = 1 得 X = 3/20 所以至少有三人 同时会写 Java 和 C++
- java千万级数据txt文件导入数据库
https://blog.csdn.net/panfanglin/article/details/13006259
- return 、break和continue的区别和作用
1).return关键字并不是专门用于跳出循环的,return的功能是结束一个方法。 一旦在循环体内执行到一个return语句,return语句将会结束该方法,循环自然也随之结束。与continue和break不同的是,return直接结束整个方法,不管这个return处于多少层循环之内。
2).continue的功能和break有点类似,区别是continue只是中止本次循环,接着开始下一次循环。而break则是完全中止循环。
3).break用于完全结束一个循环,跳出循环体。不管是哪种循环,一旦在循环体中遇到break,系统将完全结束循环,开始执行循环之后的代码。 break不仅可以结束其所在的循环,还可结束其外层循环。此时需要在break后紧跟一个标签,这个标签用于标识一个外层循环。Java中的标签就是一个紧跟着英文冒号(:)的标识符。且它必须放在循环语句之前才有作用。
- Math.round(11.5)等於多少? Math.round(-11.5)等於多少?
Math 类中提供了三个与取整有关的方法:ceil、floor、round,这些方法的作用与它们的英文名称的含义相对应,例如,ceil 的英文意义是天花板,该方法就表示向上取整,所以,Math.ceil(11.3)的结果为12,Math.ceil(-11.3)的结果是-11;floor 的英文意义是
地板,该方法就表示向下取整,所以,Math.floor(11.6)的结果为11,Math.floor(-11.6)的结果是-12;最难掌握的是round 方法,它表示“四舍五入”,算法为Math.floor(x+0.5),即将原来的数字加上0.5 后再向下取整, 所以, Math.round(11.5) 的结果为12 ,
Math.round(-11.5)的结果为-11。
- Overload(重载)和Overrided (重写)的区别。
重载:同一个类中,方法名相同,参数不同
重写:父子类中,方法名相同、参数相同、返回值类型原则上要求相同,但子类的方法权限不允许小于父类,不允许抛出比父类更多的异常。
| 位置 | 方法名 | 参数表 | 返回值 | 访问修饰符 |
方法重写 | 子类 | 相同 | 相同 | 相同或是其子类 | 不能比父类更严格 |
方法重载 | 同类 | 相同 | 不相同 | 无关 | 无关 |
- 概括解释线程的几种可用状态
1、新建(new):新建一个线程对象。
2、可运行状态(runnable):线程对象创建后,其他线程调用该对象的start()方法,该状态的线程位于可运行线程池中,等待线程调度选中,获取CPU使用权。
3、运行状态(running):可运行状态的线程获取到了cpu时间片(timeslice),执行程序代码。
4、阻塞(block):运行状态的线程因为某些原因放弃了CPU的使用权,也即让出了cpu timeslice,暂时停止运行。直到线程进入可运行状态,才有机会再次获得cpu timeslice转到运行状态。阻塞的情况分为三种:
(一)等待阻塞:运行状态的线程对象执行了wait()方法,JVM会把该线程放入等待队列(waitting queue)中。
(二)同步阻塞:运行状态的线程对象要获取同步锁时,若该同步锁被别的线程占用,则JVM就会把该线程放入锁池(lock pool)中。
(三)其他阻塞:运行状态的线程对象调用了sleep()、join()方法或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、I/O处理完毕时,线程转入可运行状态。
5、死亡(dead):线程run()、main()方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可复生。
- 在监视器(Monitor)内部,是如何做线程同步的?程序应该做哪种级别的同步?
监视器和锁在Java虚拟机中是一块使用的。监视器监视一块同步代码块,确保一次只有一个线程执行同步代码块。每一个监视器都和一个对象引用相关联。线程在获取锁之前不允许执行同步代码。
在 java 虚拟机中, 每个对象( Object 和 class )通过某种逻辑关联监视器,每个监视器和一个对象引用相关联, 为了实现监视器的互斥功能, 每个对象都关联着一把锁.
一旦方法或者代码块被 synchronized 修饰, 那么这个部分就放入了监视器的监视区域, 确保一次只能有一个线程执行该部分的代码, 线程在获取锁之前不允许执行该部分的代码
另外 java 还提供了显式监视器( Lock )和隐式监视器( synchronized )两种锁方案
- 什么是死锁
两个线程或两个以上线程都在等待对方执行完毕才能继续往下执行的时候就发生了死锁。结果就是这些线程都陷入了无限的等待中。
- 为什么集合类没有实现Cloneable和Serializable接口
克隆(cloning)或者是序列化(serialization)的语义和含义是跟具体的实现相关的。因此,应该由集合类的具体实现来决定如何被克隆或者是序列化。
- 快速失败(fail-fast)和安全失败(fail-safe)的区别是什么
Iterator的安全失败是基于对底层集合做拷贝,因此,它不受源集合上修改的影响。java.util包下面的所有的集合类都是快速失败的,而java.util.concurrent包下面的所有的类都是安全失败的。快速失败的迭代器会抛出ConcurrentModificationException异常,而安全失败的迭代器永远不会抛出这样的异常
- Java集合类框架的基本接口有哪些
Collection和Map
- Java常考面试题
https://www.nowcoder.com/ta/review-java/review?page=1
- 如何确保N个线程可以访问N个资源同时又不导致死锁?
使用多线程的时候,一种非常简单的避免死锁的方式就是:指定获取锁的顺序,并强制线程按照指定的顺序获取锁。因此,如果所有的线程都是以同样的顺序加锁和释放锁,就不会出现死锁了
- @Autowired 与@Resource的区别
@Autowired(这个注解是属业spring的) 根据类型注入,
@Resource(这个注解属于J2EE的) 默认根据名字注入,其次按照类型搜索
@Autowired @Qualifie("userService") 两个结合起来可以根据名字和类型注入
- Quartz在规定的时间内没处理完事务, 怎么办,需要配置什么?
在定时任务的配置中设置:
<property name="triggers" value=”false”>
这里默认是true , 意思就是停掉当前,启动新的任务
改成false , 意思就是如果当前有任务没有执行完,就不会开启新的任务,知道当前任务结束.
cron表达式(七子表达式),不能同时出现日和周,这两个哪个不用就用?代替
- 你在项目中使用SpringCloud的哪些组件?
服务注册组件Eureka 服务发现组件Feign 熔断器 网关 SpringCloudConfig (集中配置
管理) SpringCloudBus(消息总线)
- 你在项目中哪个业务场景使用到微服务间的调用
交友微服务 添加好友,在交友微服务中调用用户微服务的更改粉丝数与关注数的方法。
- 往宿主机安装东西的命令: rpm -ivh
- 获取jenkins密码的方法:在jenkins安装的机器上执行一下命令
cat /var/lib/jenkins/secrets/initialAdminPassword
redis相关:
https://blog.csdn.net/ligupeng7929/article/details/79603060?tdsourcetag=s_pcqq_aiomsg
- 2019年2月19日面试题
1. maven有哪些插件
clean 构建之后清理目标文件,删除目标目录。
compiler 编译java源文件
surefile 运行JUnit单元测试,创建测试报告
jar 从当前工程中构建JAR文件
war 从当前工程中构建WAR文件
Javadoc 为工程生成javadoc
antrun 从构建过程的任意阶段中运行一个ant任务集合
2. spring中bean的生命周期
3. MySQL和Oracle的区别
①Oracle是大型数据库而Mysql是中小型数据库
②Oracle支持大并发,大访问量
③MYSQL里可以用双引号包起字符串,ORACLE里只可以用单引号包起字符串
④存储过程和函数的区别:
4. JAVA异常体系
Error(错误):是程序无法处理的错误,例如JVM运行错误,内存溢出
Exception(异常):是程序本身可以处理的异常。分两大类运行时异常和非运行时异常(编译异常)。
运行时异常:都是RuntimeException类及其子类异常,如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等,属于不检查已成,程序可以选择捕获处理,也可以不处理,编译可通过。
非运行时异常 (编译异常):是RuntimeException以外的异常,必须处理,不处理则无法通过编译。
异常处理机制
抛出异常,捕捉异常
Java中throws和throw的区别
throw语句用在方法体内,表示抛出异常,由方法体内的语句处理。
throws语句用在方法声明后面,表示再抛出异常,由该方法的调用者来处理。
5.maven的三个标准生命周期
Maven的生命周期就是对所有的构建过程进行抽象和统一。
包含了项目的清理、初始化、编译、测试、打包、集成测试、验证、部署和站点生成等几乎所有的构建步骤。
三套生命周期:
clean:项目清理的处理
default(build):项目部署的处理
site: 项目站点文档创建的处理
- springboot如何获取上下文
工具类