java面试题(仅供参考)

2023-05-16

                                        java面试题(仅供参考)

框架阶段 概念宝典 1
自我介绍——P2P网贷项目 4
第三个月 基础框架篇 8
一、基础概念篇 8
1、Get和Post的区别? 8
2、List,Set,Collection,Collections的区别? 8
3、 StringBuffer、StringBuilder、String 区别? 8
4、MVC框架思想 9
5、HashMap和Hashtable的区别 9
6、网络七层协议 10
二、框架概念篇 12
Hibernate 12
Spring 18
Springmvc 29
三、JQuery 篇 38
1、jquery $(document).ready() 与window.onload的区别 38
2、你知道jquery中的选择器吗,请简单介绍一下? 39
3、jquery常用方法总结 40
4、JQuery 常用的事件 40
5、请谈一下你对Ajax的认识 41
6、ajax 三种使用方式 42
7、ajax 常用属性 42
8、Json 43
第四个月SSM框架篇 44
一、基础篇 44
1、Map介绍,以及map的底层;list介绍,以及list底层 44
2、接口和抽象类有什么区别?或者问你选择使用接口和抽象类的依据是什么? 45
3、乐观锁和悲观锁的区别?(最全面的分析) 46
二、 框架篇 47
一、SpringMVC 48
二、 Spring 50
三、mybatis 56
四、 SSM 60
五、linux 篇 62
第五个月 概念总结 64
一、 基础篇 64
1. 你对xml和json是怎么理解的? 64
2. final,finally,finalize 三者区别 65
3、什么叫GC? 66
二、数据库篇 66
1、索引的概述 66
2、oracle三层分页 67
3、数据库的三大范式和五大约束? 67
4、就业必会 复杂sql? 70
三、框架篇 72
1、你对maven是怎么理解的? 72
2、Mybatis介绍之缓存 72
3、Mybatis的批量操作数据库?(了解,并会使用) 73
4、easyui分页的实现思路? 74
5、easyui常用组件? 74
6、easyui常用组件属性及方法? 74
7、简述前台框架(easyui) 75
8、bootstrap常用组件? 76
9、bootstrap常用css样式? 76
10、session和cookie的区别? 79
11、如果项目中有异常该怎么处理?业务逻辑层能不能捕获异常?(了解) 79
四、技术篇 81
1、redis的三大特点以及优势,redis常用数据类型(标记理解,认识,必须掌握)? 81
2、什么是缓存穿透,什么是缓存雪崩,以及如何解决? 82
3、redis与memcache的区别分析 82
4、Redis 和 spring整合的步骤。Redis的使用业务场景。哪些东西不适合用缓存? 83
5、mongodb常用命令?(了解) 85
6、Redis 和Mongodb 的 区别? 87
7、Mongodb 和spring整合 步骤。 spring 提供的工具类,常见方法。 mongdb 使用的业务场景。哪些业务使用Mongodb 反而会麻烦? 87
8、简单介绍一下你对Webservice的理解 88
9、HttpClient的讲解 90
人事面试问题汇总 90
1.为什么要离职? 90
2.薪资多少? 91
3.以前做过的项目? 91
4.说说你的优缺点? 91
5.你能做一个自我介绍? 91
6.介绍一下你以前的公司? 91
7.你对加班有什么看法? 92
8.你还有什么问题吗? 92
9.你为什么还没有找到合适的岗位? 92
10.谈谈你未来几年的职业规划? 92
11.你的业余爱好是什么? 92
12.你觉得对这个工作感兴趣吗? 92
13.谈谈你的一个失败的经历? 92
14.说说你会在我们工作待多久? 93
15. 简单介绍一下你的缺点? 93

自我介绍——P2P网贷项目
您好,我先做一下自我介绍吧,我叫XXX,我从事java开发,到现在工作有四年的时间了。我上家公司是XXX,在这四年开发中主要接触过电商系统(易尚商城),网贷系统(优投网贷)、办公系统(协同办公)等。

【项目二】P2P网贷

我最近做了一个P2P网贷的项目。这个项目主要目的是针对个体(个人、企业或组织)和个体之间通过互联网平台实现的直接借贷。整个项目分为前台系统(用户访问平台)与后台管理系统两个项目。
前台项目主要涉及的模块:是债券模块(展示债券以及用户购买时生成订单)、出借模块、借款模块、推广模块、信息披露模块、用户管理模块(登录注册、个人中心)。判断如果为新用户还涉及到一个新手引导流程。
后台系统的模块:则分为用户管理模块,业务管理模块(债券的发布、上下架及调整、合同的POI导出),推广管理模块、统计管理模块(HighCharts报表完成用户登录及注册次数的统计、每日购买量的统计、资金统计等等)基本设置(前台信息披露模块中展示的公司基本信息)、财务管理(主要涉及到用户充值管理,线下充值,提现管理,用户信用管理,用户担保管理,不良债权转让管理,商城的退款管理,平台调账管理)等等。
我在项目中主要负责的是前台的债券模块、出借模块、借款模块、业务管理、财务管理模块。
2.1债券模块:
首先是将后台上架的债权信息展示给前台,购买流程为当用户点击购买某个债权时首先判断债券剩余的数量是否足够,如果足够则生成订单(此时订单状态为0未付款)并在库存中减去相应的数量,该订单如果在15分钟内未完成付款操作,则自动取消。生成订单后根据用户录入的银行卡信息调出相应的银行接口让用户进行付款(这里也可以添加新的银行卡)。用户这边付款后再通过银行接口返回的流水号查询是否付款成功。付款成功则将订单状态修改为1已付款,购买成功并通知用户,同时通知后台客服对订单做出处理。
如果两个用户同时购买了100份库存只有100的债权?
如果两个用户同时购买了100份库存只有100的债权。则只会有一个用户购买成功。因为此处使用RabbitMQ消息队列的原因。消息队列是根据日志信息从左到右执行的。所以即使是同时发出了生成订单的请求,在执行完左侧生成的订单消息之后,因为数据库中库存已经不够了,所以第二个订单生成是不会成功的。
业务管理模块中主要涉及的有债券管理,催收管理,合同管理,借款管理。
2.2 债券管理:
比如债券的发布、上下架及调整,当债权信息有了更新以后。在业务逻辑层直接调用前台项目中重新生成静态化页面(freemarker)的方法将之前的债券展示信息替换掉。替换成功后才会提交事务,避免前台展示的数据与后台数据库中的数据出现偏差。
催收管理模块:主要是根据用户还款的时间来及时给用户提醒。通过定时器来每天进行一次判断。比如说在距离还款还有一周的时候,调用短信接口(httpclient)来给用户发送提示短信进行通知,在还款当天再次提醒用户逾期将会产生违约金等。在逾期三天之后会提醒客服对客户进行催收以及对催收情况的统计。逾期一个月以上的用户可添加至黑名单。
订单生成后会自动添加到合同列表中。在合同管理中可以进行详情查看以及直接将合同导出为Word文档进行打印。
借款管理:首先用户选择相应的借款类型,在用户发出了借款申请后。首先是由审核部门对该用户信用级别(黑名单中的用户无法发出申请/信用等级越高的用户可申请的额度就越高,同时也根据抵押物来判断申请借款的金额)以及抵押物的一个审核。(此时默认状态为审核中),在审核通过后状态变更为已审核未发布,此时业务部门可以进行该借款的发布。发布以后前台用户就可以看到该信息并且借贷给该用户。当金额足够以后将状态变更为“已满标”。同时由财务部门将钱打给申请借款的用户。
2.3 财务管理:我在这个模块中主要负责充值管理,线下充值,提现管理这几个模块。
充值管理与线下充值管理:主要是对用户充值到此平台上的金额的一个记录的展示。考虑到安全问题,在该平台中只能对它进行查询而不能进行更改操作。且在该用户余额进行购买债券或借出操作时会有一个审核。
提现管理:用户在前台系统发出提现申请后,该条信息就会在提现管理中展示出来(状态为:申请提现),首先由业务部门核实后更改状态为(已审核,未打款),然后由财务部门进行打款。将状态更改为已提现。

后台管理系统包括:会员管理,业务管理,系统管理,财务管理,统计管理,推广管理等主要模块

2.4会员管理:是对会员信息统计和管理(包括个人信息,企业信息,机构信息),会员的认证管理,留言管理等。
会员认证管理:通过该功能新注册用户可以通过必要的用户认证后获得非0的借款信用额度而拥有有效的借款申请权限,在通过非必须、额外的用户认证来更进一步提高用户的借款信用额度,使用户可以在同一时间取得更大额度的借款。
必要的用户认证:主要包括:身份证认证,工作认证,收入认证,芝麻信用报告认证等。
额外的用户认证:主要包括:学历认证,房产认证,技术职称认证,购车证明等。
留言管理:主要是针对会员在“帮助中心”的留言,及时进行恢复。
2.5 业务管理:是我们网贷的核心模块,主要有理财管理,借款管理,催收管理,合同管理等
2.6 理财管理:有在线债券的管理和线上债券的转让管理。
2.7 借款管理:有借款管理、个人借款意向管理和企业借款意向管理。借款管理中主要是负责对借款申请的审批(主要负责审查用户的借款类型和抵押物以及其他申请是否合理),并负责在前台展示借款信息的页面进行招标。招收到的资金已满的话,后台进行审核后,做放款处理。
2.8 催收管理:代还款列表,催收记录,黑名单。
代还款列表展示的是借贷用户的信息,便于后台人员的统计和催收的通知,催收的实现使用的是定时器+Webservice来实现的,正常还款的用户通过使用定时器,在还款期限前三天通过调用Webservice短信接口,发送短信给用户,提醒用户还款。对于逾期3—7天用户,通过定时器实现线上的催收(发送短信,还款期限已逾期),对于逾期7天以上的用户,通过定时器通知后台管理人员,通过Poi技术导出相对应的逾期用户信息,通过线下催款的方式催收贷款。对于严重逾期的用户,线下催收的同时加入黑名单,不在提供服务给该用户。
2.9 系统管理:主要有后台账号,系统日志,业务推广等,需要使用shiro权限框架.
后台账号主要分为业务员账号管理,管理员账号管理,用户账号管理等,在这模块中要实现登录用户的权限限制。
因为涉及到资金的安全,所以我们做了日志记录的统计,所有增删改的操作都要生成相应的日志,做一个日志的统计,方便责任到人。
业务推广板块主要是对一些活动的推广,发送邮件和站内推广信给用户。
2.10 财务管理:主要有资金管理,资金明细等。
资金管理中包括:充值管理,线下充值管理,提现管理,放款管理,用户信用管理,用户担保管理等
资金的明细主要是对平台资金的流向做相应的统计,通过Poi导出到做线下的会议使用。
2.11 统计管理:主要有用户统计,资金统计,业务统计,统计报表等(使用highcharts技术),主要用于业务的推广方式。
用户统计:主要是针对用户注册的方式的统计,方便后期的业务推广。
资金统计:是看平台的资金的流动情况和盈亏情况。
业务统计:平台业务情况的查看,以及业务后期的推广重心。
2.12 推广管理:推广奖励,奖励金管理,活动管理等。
第三个月 基础框架篇
一、基础概念篇
1、Get和Post的区别?
1.get是从服务器上获取数据,post是向服务器传送数据,
2.get传送的数据量较小,不能大于2KB。post传送的数据量较大,一般被默认为不受限制。
3.get安全性非常低,post安全性较高。但是执行效率却比Post方法好。
4.在进行文件上传时只能使用post而不能是get。
2、List,Set,Collection,Collections的区别?
List和Set都是接口,他们都继承于接口Collection,List是一个有序的可重复的集合,而Set的无序的不可重复的集合。 Collection是集合的顶层接口,Collections是一个封装了众多关于集合操作的静态方法的工具类,因为构造方法是私有的,所以 不能实例化。
List接口实现类有ArrayList,LinkedList,Vector。ArrayList和Vector是基于数组实现的,所以查询的时候速度快,而在进行增加和删除的时候速度较慢LinkedList是基于链式存储结构,所以在进行查询的时候速度较慢但在进行增加和删除的时候速度较快。又因为Vector是线程安全的,所以他和ArrayList相比而言,查询效率要低。
3、StringBuffer、StringBuilder、String 区别?
这三个类之间的区别主要是在两个方面,即运行速度和线程安全这两方面。
1.首先说运行速度,或者说是执行速度,在这方面运行速度快慢为:StringBuilder > StringBuffer > String
String最慢的原因:
String为字符串常量,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的。以下面一段代码为例:
1 String str=“abc”;
2 System.out.println(str);
3 str=str+“de”;
4 System.out.println(str);
2. 再来说线程安全
在线程安全上,StringBuilder是线程不安全的,而StringBuffer是线程安全的
如果一个StringBuffer对象在字符串缓冲区被多个线程使用时,StringBuffer中很多方法可以带有synchronized关键字,所以可以保证线程是安全的,但StringBuilder的方法则没有该关键字,所以不能保证线程安全,有可能会出现一些错误的操作。所以如果要进行的操作是多线程的,那么就要使用StringBuffer,但是在单线程的情况下,还是建议使用速度比较快的StringBuilder。
3. 总结一下
  String:适用于少量的字符串操作的情况
  StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况
  StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况
4、MVC框架思想
MVC是一种分层架构的思想,主要是将Web项目结构进行分成controller、Model、View三个层次,在初期设计中,MVC也包含了持久层。Controller层作为控制层,主要是响应用户请求,接收并校验用户参数(因为用户有可能通过某种方式跳过页面的js验证,比如直接在地址栏发起请求),调用业务逻辑层,也就是Mode层完成业务操作,最后根据业务处理的结果,完成页面跳转到View层。在Model层中,主要是完成了各种业务逻辑操作。View层主要负责视图展示,通常不应该设计业务操作,View层常用的技术包括:html、jsp等等。
5、HashMap和Hashtable的区别
HashMap和Hashtable都实现了Map接口,但决定用哪一个之前先要弄清楚它们之间的分别。主要的区别有:线程安全性,同步(synchronization),以及速度。
1、HashMap几乎可以等价于Hashtable,除了HashMap是非synchronized的,并可以接受null(HashMap可以接受为null的键值(key)和值(value),而Hashtable则不行)。
2、HashMap是非synchronized,而Hashtable是synchronized,这意味着Hashtable是线程安全的,多个线程可以共享一个Hashtable;而如果没有正确的同步的话,多个线程是不能共享HashMap的。Java 5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的扩展性更好。
3、另一个区别是HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。所以当有其它线程改变了HashMap的结构(增加或者移除元素),将会抛出ConcurrentModificationException,但迭代器本身的remove()方法移除元素则不会抛出ConcurrentModificationException异常。但这并不是一个一定发生的行为,要看JVM。这条同样也是Enumeration和Iterator的区别。
4、由于Hashtable是线程安全的也是synchronized,所以在单线程环境下它比HashMap要慢。如果你不需要同步,只需要单一线程,那么使用HashMap性能要好过Hashtable。
5、HashMap不能保证随着时间的推移Map中的元素次序是不变的。
6、网络七层协议
谈到任何联网的协议,我们就必须要谈到OSI(网络七层协议模型),必须遵循这个协议模型,我们的手机和电脑才可以联网通信,首先来看一下OSI
OSI
OSI是一个开放性的通信系统互连参考模型,他是一个定义得非常好的协议规范。OSI模型有7层结构,每层都可以有几个子层。
应用层
示例:TELNET,HTTP,FTP,NFS,SMTP等。
表示层
示例:加密,ASCII等。
会话层
示例:RPC,SQL等。
传输层
示例:TCP,UDP,SPX。
网络层
示例:IP,IPX等。
数据链路层
示例:ATM,FDDI等。
物理层
示例:Rj45,802.3等。
简单了解OSI之后我们来看一下我们手机与电脑通信,所能够使用的两种数据通信,一种是HTTP请求,一种是Socket通信,HTTP是属于短连接,适合新闻,订票信息等客户端发起请求,每一次请求结束,自动断开连接。而Socket是属于长连接,适合游戏,聊天等实时数据。
手机能够联网都是需要基于OSI协议模型,同时手机底层实现了TCP/IP协议。
以下为了解部分:
下面简单介绍一下TCP/IP协议
TCP/IP
建立起一个TCP连接需要经过“三次握手”:
第一次握手:客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
握 手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。理想状态下,TCP连接一旦建立,在通信双方中的任何一方主动关闭连 接之前,TCP 连接都将被一直保持下去。断开连接时服务器和客户端均可以主动发起断开TCP连接的请求,断开过程需要经过“四次握手”(过程就不细写 了,就是服务器和客户端交互,最终确定断开)
同时Socket可以支持不同的传输层协议(UDP),那我们平时为什么不使用UDP呢,我们现在来看一下UDP与TCP的区别
TCP UDP
是否连接 面向连接 面向非连接
传输可靠性 可靠 不可靠
应用场合 传输大量数据 少量数据
速度 慢 快

二、框架概念篇
Hibernate
1、hibernate的概述?
hibernate是一个对JDBC进行轻量级封装的持久层框架
hibernate是全自动的(将常用方法进行了封装,不用手动进行结果集的解析)
hibernate是跨数据库的,
hibernate的开发效率高于jdbc,
hibernate使用的hql语句,
但是在最后操作数据库是hql语句会转化成sql语句去执行,
hibernate操作的是对象from实体类名
2、Hibernate 多表联查的实现方式核心代码?
hibernate很多实现都是靠喜欢配关系,但是如果两张表,数据量都非常大的时候,并不合适配关系。
例如:student表和score表需要做联合查询。
1)sql: select s.id,s.name,sc.score from student as s,score as sc where s.id = sc.userId;(字段都是用的数据库中字段名称)
2)HQL: select s.id,s.name,sc.score from Student as s,Score as sc where s.id = sc.userId;(上面字段都是 javabean的属性)
如果我们按1)查询的话,必须调用 session.createSQLQuery();方法
如果按2)查询,还是调用 session.createQuery();
只是要注意,平时我们查询的时候,例如:“from Student ”查询的结果集封装的全都 是student对象,但是2)执行的结果集里面不是对象,而是一系列数组。需要转换成需要的样式。

3、Hibernate中的五大核心类和接口?
1.Configuration(类) : 加载配置文件hibernate.cfg.xml文件中的配置信息,从而得到:
1).hibernate的底层信息:数据库连接,jdbc驱动,方言(dialect),用户名 ,密码
2).hibernate的映射文件(*.hbm.xml)
2.SessionFactory(接口):通过configuration创建的sessionFactory,可以用来获得session.openSession(); sessionFactory是线程安全的,里面保存了数据的配置信息和映射关系
3.Session(接口):不是线程安全的,相当于jdbc中connection,我们可以使用session来操作数据库负责保存、更新、删除、加载和查询对象,是一个非线程安全的,避免多个线程共享一个session,是轻量级,一级缓存。
4.Transaction(接口):session.beginTransaction(); //由于Hibernate增删改需要使用事务所以这里要开启事务session.getTransaction().commit();//提交,我们一般使用Transaction来进行事务的管理commit(提交)rollback(回滚)
5.Query(接口):我们一般用来进行数据的查询操作
4、Hibernate中两种占位符是(?)和(:变量名)?
1). ?的赋值方式: query对象.setParameter(index,value)
2). :变量名赋值方式: query对象.setParameter(“变量名”,value)
5、Hibernate中query对象的常用方法?
query对象.executeUpdate() 方法对数据进行修改或者删除
query对象.uniqueResult() 方法返回单条记录,获取唯一结果集
query对象.setFirstResult() 方法设置结果集开始位置,查询开始条数
query对象.setMaxResults() 方法设置每页查询条数
query对象.list() 方法返回查询结果集
6、Hibernate中session 对象的常用方法有?
1.find(String queryString) 查询返回list结果集 ,根据HQL查询字符串来返回实例集合find方法在执行时会先查找缓存,如果缓存找不到再查找数据库,如果再找不到就会返回null。
2.save(Object entity) 添加 保存新的实例
3.saveOrUpdate(); 添加或修改 有id是修改 没id 是更新
4.delete(Object entity); 删除 删除指定的持久化实例
5.update(Object entity); 修改 更新实例的状态 实例必须为持久化状态
6.get(Class entityClass,Serializable id)根据ID查询 根据主键加载特定持久化实例
7.load();根据唯一标识获得 对象 延迟加载
7、 get 和 load 的区别,以及注意事项?
1).load是延迟加载(懒加载,按需加载)调用load方法后不会立即发送SQ语句,当访问实体属性的时候才会去发送SQL语句,如果访问的实体不存在,则返回ObjectNotFoundException(对象不存在异常)
2).get 是立即加载,当调用get方法后立即发送sql语句,当访问的实体不存在的时候,则返回null,get(Class entityClass,Serializable id)根据主键加载特定持久化实例。
在程序中一般先用 Assert.isTrue断言id是否大于0,若大于0继续执行,若查到数据,则返回实例,否则返回空不同于load,load若有数据则返回实例,否则报出ObjectNotFoundEcception异常,相比来说get效率高些。
注意:
load支持懒加载通过lazy=“true”设置,如果lazy=“false”,则load不再进行懒加载,默认情况下lazy=“true”。
8、五个hibernate主键生成策略并分别描述?
1).Increment:先查询出最大id,在此基础上加1;hibernate框架会自动处理
2).Sequence(Orade) :oracle 数据库会自动处理
    3).Assigned:人工指派(重复插入数据时会违反数据唯一性)
    4).native:(数据库本地生成策略,适用多个数据库),适用于mysql.oracle,sqlserver,如果是orade数据库则默认使用的序列名为hibernate-sequence
    5).uuid:生成一个32位,不会重复的主键,可以达到真正的跨数据库(通常来说对应的应该是string数据类型)
    6).foreign:通常在一对一主键的时候使用,基于外键的主键生成策略
9、Hibernate的二级缓存。Ehcache介绍
1).Hibernate缓存分为:
一级缓存即session缓存也叫事务级别的缓存以及二级缓存sessionFactory即应用级别的缓存,还有查询缓存即三级缓存。
一级缓存的生命周期和session的生命周期保持一致,hibernate默认就启用了一级缓存,不能将其关闭,可以通过session.clear()和session.evict(object)来管理一级缓存。其中get,load,iterate都会使用一级缓存,一级缓存缓存的是对象。
二级缓存的生命周期和sessionFactory的生命周期保持一致,可以跨session,被多个session共享,hibernate3默认开启二级缓存,也可以手动开启并指定缓存插件如ehcache,oscache等。二级缓存也只能缓存对象。
三级缓存也叫查询缓存,查询缓存是针对普通属性结果集的缓存,对实体对象的结果集只缓存id。对query.list()起作用,query.iterate不起作用,也就是query.iterate不使用查询缓存
2).Ehcache的介绍:
2.1).Ehcache是一个非常轻量级的缓存实现,而且从1.2之后就支持了集群,而且是hibernate默认的缓存provider。EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider。
2.2).Ehcache的分布式缓存有传统的RMI,1.5版的JGroups,1.6版的JMS。分布式缓存主要解决集群环境中不同的服务器间的数据的同步问题。
2.3).使用Spring的AOP进行整合,可以灵活的对方法的返回结果对象进行缓存。
2.4).CachingFilter功能可以对HTTP响应的内容进行缓存。
2.5).主要特性:
1. 快速.
2. 简单.
3. 多种缓存策略
4. 缓存数据有两级:内存和磁盘,因此无需担心容量问题
5. 缓存数据会在虚拟机重启的过程中写入磁盘
6. 可以通过RMI、可插入API等方式进行分布式缓存
7. 具有缓存和缓存管理器的侦听接口
8. 支持多缓存管理器实例,以及一个实例的多个缓存区域
9. 提供Hibernate的缓存实现等等。

10、事务的概述
在数据库中,所谓事务是指一组逻辑操作单元即一组sql语句。当这个单元中的一部分操作失败,整个事务回滚,只有全部正确才完成提交。
事务的ACID属性

  1. 原子性(Atomicity)
    原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,
    要么都不发生。
  2. 一致性(Consistency)
    事务必须使数据库从一个一致性状态变换到另外一个一致性状态。(数据不被破坏)
  3. 隔离性(Isolation)
    事务的隔离性是指一个事务的执行不能被其他事务干扰.
  4. 持久性(Durability)
    持久性是指一个事务一旦被提交,
    它对数据库中数据的改变就是永久性的.
    在JDBC中,
    事务默认是自动提交的,
    每次执行一个 SQL 语句时,如果执行成功,
    就会向数据库自动提交,而不能回滚
    为了让多个 SQL 语句作为一个事务执行:
    (1)执行语句前调用 Connection 对象的 setAutoCommit(false);
    以取消自动提交事务
    (2)在所有的 SQL 语句都成功执行后,调用 commit(); 方法提交事务
    (3)在出现异常时,调用 rollback(); 方法回滚事务。
    11、Hibernate常用注解?
    @Entity:声明实体bean,每一个持久化POJO类都是一个实体bean,这可以通过在类的定义中使用@Entity注解来进行声明:
    @Id:注解则声明了该实体bean的标识属性,对应相应表使用id列作为主键列
    @Table:是类一级的注解, 通过@Table注解可以为实体bean映射指定表(table),目录(catalog)和schema的名字. 如果没有定义@Table,那么系统自动使用默认值:实体的短类名(不附带包名).
    @Transient:自动生成表时忽略某个字段
    @GeneratedValue:定义该标识符的生成策略
    AUTO - 可以是identity column类型,或者sequence类型或者table类型,取决于不同的底层数据库.
    TABLE - 使用表保存id值
    IDENTITY - identity column
    SEQUENCE - sequence
    @OneToOne注解可以建立实体bean之间的一对一的关联.
    @ManyToOne注解来定义多对一关联

Spring
1、spring概述
我认为spring就是一个框架的集成器,通常使用spring来管理action层和DAO层。
Spring本身有很多的组件,比如:MVC、IOC、AOP、DaoSupport等等。IOC本身也就是一个容器,它管理了所有的bean和bean之间的依赖关系。IOC也叫作控制反转,核心是BeanFactory。也就意味着IOC是基于工厂模式设计的,同时这个工厂生产的bean默认是单例的。如果想修改单例变成多实例,则需要修改bean的scope属性,值是prototype。
在没有使用IOC以前,程序员需要自己在对应的类中new相关依赖的对象。比如UserAction依赖于UserService完成业务操作,而UserService又依赖于UserDAO完成数据库操作。所以需要在action中new servcie,在service中new DAO。这样的方式,是由程序员来管理了对象的生命周期和他们之间的依赖关系,耦合度很高,不利于程序的拓展。所以通过IOC来管理bean和依赖关系,可以解耦合。我们将所有的action、service和dao等类定义成IOC的一个bean组件,此时类的实例化就交给了IOC的beanFactory,由工厂来负责实例化bean的对象。
IOC有三种注入方式,属性注入、构造器注入和接口注入。接口注入只是spring提出的设计,并没有具体的实现,所以常用的注入方式是属性注入。属性注入就是在bean的标签中,配置property标签设定注入其他的bean。要求注入的bean在被注入的bean中要存在一个全局的私有变量,并提供set方法。这样就可以实现了依赖关系的注入。如果需要很多的bean,则直接注入就可以。如此操作会导致bean标签的配置比较冗余复杂,所以spring提供了autowried的自动装配方式,可以byName也可以byType。后续的版本中,spring还提供了annotation的方式,不需要再去定义多余的bean标签,而是直接在对应的类上面声明注解就可以了。常用的注解有:@controller、@Service、@Repository、@Component、@AutoWried、@Resource等。
除了IOC以外,项目中通常通过AOP来实现事务控制。AOP就是面向切面编程,一般事务我们会控制在service层,因为一个service有可能会调用到多个DAO层的方法,所以只有当一个service方法执行成功后,再提交或者回滚事务。具体的配置方式是:在applicationContext.xml中,配置aop:config标签,指定事务控制在service层。除此还需要配置事务的管理类transactionManager,将这个transactionManager指定给事务管理的bean,并且配置事务的传播特性、隔离级别、回滚策略以及只读事务read-only等等。
Spring默认的传播特性是如果当前上下文中存在事务则支持当前事务,如果没有事务,则开启一个新的事务。还有另外一个传播特性是在项目中经常用的,REQUIRES_NEW这个配置,这个属性指的是总是开启一个新的事务,如果当前上下文中存在一个事务,则将当前的事务挂起后开启新的事务。比如说:在一个本来是只读事务的操作中,想加入写操作的时候,就使用REQUIRES_NEW。关于事务的隔离级别,一般使用默认的配置提交读。也就是说,事务提交以后,才能访问这条数据。除了事务控制以外,我们通常还可以使用AOP去完成一些特殊操作,比如日志控制、安全校验等等。这么做的目的就是将功能操作的代码从实际的业务逻辑操作出分离出来。实现的方式是通过代理模式,真正完成操作的不是实际的业务对象而是代理对象。
代理模式有静态代理和动态代理,实现的方案也有两种,一种是基于JDK的Proxy代理类,另外一种则通过CGLIB来实现。实现AOP的方式,主要是在applicationContext中定义一个AOP处理类,这就是一个普通的bean,在类中定义要执行的方法。然后去配置一个aop:config标签,在标签中定义aop:aspect切面,在切面中关联刚才定义好的处理类bean。然后在切面标签中配置aop:pointcut切入点,切入点就指的是在哪个类的哪个方法上加入代理事务,然后配置通知模型。AOP的通知模型中包含:前置通知、后置通知、最终通知、异常通知、环绕通知。这几个通知模型表示在方法执行以前、执行以后、最终执行、当遇到异常时执行以及前后都执行。在执行的AOP切面方法中,可以通过JoinPoint连接点来获得当前被代理的对象以及被代理对象要执行的方法和方法的参数。除了IOC和AOP,我们经常还会使用到spring的DaoSupport。主要是spring提供了对hibernate和myBatis等持久型框架的接口。比如HibernateDaoSupport,和sqlSessionDaoSupport。如果DAO继承了HibernateDaoSupport,则需要在对应的bean中注入sessionFactory。而sessionFactory是通过IOC加载的。

2、Spring源码学习之spring设计理念和整体架构(了解)
1.Spring的设计理念:在Java EE的应用开发中,支持POJO和使用JavaBean的开发方式, 使应用面向接口开发,充分支持00 ( 面向对象) 的设计方法。
2.Spring的整体架构:

1.SpringloC:包含了最为基本的IoC容器BeanFactory的接口与实现,也就是说,在这个Spring的核心包中,不仅定义了IoC容器的最基本接口(BeanFactory),也提供了一系列这个接口的实现,如XmlBeanFactory就是一个最基本的BeanFactory (IoC容器),从名字上可以看到,它能够支持通过XML文件配置的Bean定义信息。除此之外,SpringIoC容器还提供了一个容器系列,如SimpleJndiBeanFactory、 StaticLismbleBeanFactor等。我们知道,单纯一个IoC容器对于应用开发来说是不够的.为了让应用更方便地使用IoC容器 ,还需要在IoC容器的外围提供其他的支持 ,这些支持包括Resource访问资源的抽象和定位等 ,所有的这些 ,都是这个Spring IoC模块的基本内容。另外,在BeanFactory接口实现中,除了前面介绍的像BeanFactory那样最为基本的容器形态之夕外,Spring还设计了IoC容器的髙级形态ApplicaticmContext应用上下文供用户使用,这些ApplicationConlext应用上下文 ,如FileSystemXmlApplicationContext,ClassPathXmlAppIicationContext,对应用来说, 是IoC容器中更面向框架的使用方式,同样,为了便于应用开发,像国际化的消息源和应用支持事件这些特性,也都在这个
模块中配合IoC容器来实现,这些功能围绕着IoC基本容器和应用上下文的实现,构成了整个Spring IoC模块设计的主要内容。

2.SpringAOP: 这也是Spring的核心模块, 围绕着AOP的增强功能,Spring集成了AspectJ作为AOP的一个特定实现,同时还在JVM动态代理/CGLIB的基础上, 实现了—个AOP框架 ,作为Spring集成其他模块的工具,如TransactionProxyFactoryBean
声明式事务处理,就是通过AOP集成到Spring中的。在这个模块中,Spring AOP实现了一个完整的建立AOP代理对象,实现AOP拦截器,直至实现各种Advice通知的过程。在对这个模块的分析中可以看到,AOP模块的完整实现是我们熟悉AOP实现技术的一
个不可多得的样本。

3.Spring MVC:对于大多数企业应用而言, Web应用已经是一种普遍的软件发布方式,而在Web应用的设计中, MVC模式已经被广泛使用了。 在java的社区中,也有很多类似的MVC框架可以选择,而且这些框架往往和WebUI设计整合在一起,对于定位于提供整体平台解决方案的Spring,这样的整合也是不可缺少的。Spring MVC模块以DispatcherServlet为核心,实现了MVC模式,包括怎样与Web容器环境的集成,Web请求的拦裁.分发、处理和ModelAndView数据的返回,以及如何集成各种UI视图展现和数据表现,如PDF,Excel等, 通过这个模块,可以完成Web的前端设计。

4.Spring JDBC/SpringORM:对于关系数据库的处理, Java提供了JDBC来进行操作,但在实际的应用中,单纯使用JDBC的方式还是有些繁琐, 所以在JDBC规范的基础上,Spring对JDBC做了一层封装,使通过JDBC完成的对数据库的操作更加简洁, SpringJDBC包提供了JdbcTemplale作为模板类 ,封装了基本的数据库操作方法,如数据的査询、更新等,另外, SpringJDBC还提供了RDBMS的操作对象,这些操作对象可以使应用以更面向对象的方法来使用JDBC, 比如可以使用MappingSqlQuery将数据库数据记录直接映射到对象集合,类似一个极为简单的ORM 工具。
除了通过SpringJDBC对数据库进行操作外,Spring还提供了许多对ORM工具的封装, 这些封装包括了常用的ORM工具,如Hibernate iBatis等,这一层封装的作用是让应用更方便地使用这些ORM 工具,而不是替代这些ORM工具,比如可以把对这些工具的使用和Spring提供的声明式事务处理结合起来。同时, Spring还提供了许多模板对象,如HibernateTemaplate这样的工具来实现对Hibernate的驱动,这些模板对象往往包装使用Hibernate的一些通用过程,比如Session的获取和关闭、事务处理的关联等,从而把一些通用的恃性实现抽象到Spring中来,更充分地体现了Spring的平台作用。

5.Spring事务处理:Spring事务处理是一个通过Spring AOP实现自身功能增强的典型模块。在这个模块中, Spring把在企业应用开发中事务处理的主要过程抽象出来。这个声明式事务处理的实现,使开发人员只需要在IoC容器中对事务属性进行配置即可完成,同时, 这些事务处理的基本过程和具体的事务处理器实现是无关的,也就是说,应用可以选择不同的具体的事务处理机制,如JTA,JDBC, Hibernate等。 因为使用了声明式事务处理.具体的事务处理机制被纳入Spring事务处理的统一框架中完成 , 并完成与具体业务代码的解耦。 在这个模块中,可以看到一个通用的实现声明式事务处理的基本过程,比如怎样配置事务处理的拦截器,怎样读人事务配置属性, 并结合这些事务配置属性对事务对象进行处理,包栝事务的创建、挂起、提交、回滚等基本过程, 还可以看到具体的事务处理器(DataSourceTransactionManage,
HibernateTransactionManager、JtaTransactionManager等) 是怎样封装不同的事务处理机制(JDBC、 Hibernate, JTA等) 的。

6.Spring远端调用:Spring为应用带来的一个好处就是能够将应用解耦。应用解耦,一方面可以降低设计的复杂性,一方面,可以在解耦以后将应用模块分布式地部署,从而提髙系统整体的性能。 在后一种应用场景下, 会用到Spring的远端调用, 这种远
端调用是通过Spring的封装从Spring应用到Spring应用之间的端到端调用,在这个过程中,通过Spring的封装, 为应用屏蔽了各种通信和调用细节的实现,同时. 通过这一层的封装 ,使应用可以通过选择各种不同的远端调用来实现, 比如可以使用HTTP
调用器(以HTTP协议为基础的), 可以使用第三方的二进制通信实现Hessian/Burlap甚至还封装了传统Java技术中的RMI调用。

7.Spring应用。

小结:在我们平时的开发中,用到最多的场景就是使用SSH框架来完成企业应用的开发,取代传统的EJB笨重的开发模式。在SSH架构中 Struts作为Web UI层、 Spring作为中间件平台, Hibernate作为数据持久化工具(ORM工具) 来操作关系数据库。在这个架构中, Hibernate是一个独立的ORM数据持久化产品。比较Spring JDBC和Hibernae对数据库操作的支持,对Spring来说,其对数据持
久化的支持,虽然也有JDBC的封装,可以完成一些将简单的数据记录到Java数据对象的转换和映射工作,但和Hibernate相比, 功能上毕竞还是有一些单薄,比如Hibernate还提供了各种数据的査询、方便的对象和关系数据的映射等。因此,在大多数应用中,将Hibernate和Spring—起使用是非常普遍的,因为一方面Hibenate提供了完整的和已经成为事实标准的功能,另一方面, Spring也提供了与Hibernated的集成和封装,包括声明式事务处理的封装等。对于Web 层而言,尽管Spring提供了自己的MVC实现,但与Struts的流行程度相比,这个Spring MVC的使用并不广泛, 毕竟在Web开发领域, Struts成名更早。在这个架构组合中,Spring起到的是一个应用平台的作用,通过Spring的集成,可以让应用在直接部署在Tomcat这个Web服务器上 ,因为作为一个直接依赖JVM的轻量级框架, Spring的部署方式就是一个简单的jar包, 不需要以一个J2EE应用服务器的形式出现,从而使整个应用在Tomcat这样的Web服务器上直接运行起来,非常简洁。

Spring的优点:
1.非侵入性:其目标是使应用程序代码对框架的依赖最小化,应用代码可以在没有Spring或者其他容器的情况下正常运行
2.一致性的编程:使应用直接使用POJO开发 ,从而可以与运行环境 (如应用服务器) 隔离开来。
3.Spring推动应用的设计凤格向面向对象及面向接口编程转变,提髙了代码的重用性和可测试性。
4.Spring改进了体系结构的选择,虽然作为应用平台, Spring可以帮助我们选择不同的技术实现, 比如从Hiberante到其他ORM工具,从Struts切换到Spring MVC,尽管我们通常不会这样做,但是我们在技术方案上选择使用Spring作为应用平台, Spring至少为我们提供了这种可能性和选择, 从而降低了平台锁定的风险

3、Spring的常见注解。
1、@Controller
在SpringMVC 中,控制器Controller 负责处理由DispatcherServlet 分发的请求,它把用户请求的数据经过业务处理层处理之后封装成一个Model ,然后再把该Model 返回给对应的View 进行展示。在SpringMVC 中提供了一个非常简便的定义Controller 的方法,你无需继承特定的类或实现特定的接口,只需使用@Controller 标记一个类是Controller ,然后使用@RequestMapping 和@RequestParam 等一些注解用以定义URL 请求和Controller 方法之间的映射,这样的Controller 就能被外界访问到。此外Controller 不会直接依赖于HttpServletRequest 和HttpServletResponse 等HttpServlet 对象,它们可以通过Controller 的方法参数灵活的获取到。
@Controller 用于标记在一个类上,使用它标记的类就是一个SpringMVC Controller 对象。分发处理器将会扫描使用了该注解的类的方法,并检测该方法是否使用了@RequestMapping 注解。@Controller 只是定义了一个控制器类,而使用@RequestMapping 注解的方法才是真正处理请求的处理器。单单使用@Controller 标记在一个类上还不能真正意义上的说它就是SpringMVC 的一个控制器类,因为这个时候Spring 还不认识它。那么要如何做Spring 才能认识它呢?这个时候就需要我们把这个控制器类交给Spring 来管理。有两种方式:
  (1)在SpringMVC 的配置文件中定义MyController 的bean 对象。
  (2)在SpringMVC 的配置文件中告诉Spring 该到哪里去找标记为@Controller 的Controller 控制器。
2、@Resource和@Autowired
@Autowired为Spring提供的注解,需要导入包org.springframework.beans.factory.annotation.Autowired;只按照byType注入。
@Autowired注解是按照类型(byType)装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它的required属性为false。如果我们想使用按照名称(byName)来装配,可以结合@Qualifier注解一起使用。
@Resource默认按照ByName自动注入,由J2EE提供,需要导入包javax.annotation.Resource。@Resource有两个重要的属性:name和type,而Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。
3、@Component、@Repository、@Service
@service 声明是业务层,创建bean实例。
@Repository声明是持久层,创建bean实例。
@Component 声明是创建bean实例

4、Springmvc 和 spring的关系
springMVC位于spring web端的一个框架,是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将web层进行职责解耦。附:基于请求驱动指的就是使用请求-响应模型。
从名字上就可以窥探出,Spring>SpringMVC,那么事实上,spring和SpringMVC是一种父子关系。SpringMVC是spring扩展出的一个应用于web端的框架。在这里需要注意的一点,就是到底什么是父子容器关系:
spring主要的作用是黏合其他模块组件,进行统一管理,springmvc则主要是负责web端。那么,我们都知道,我们在应用spring的时候,可以使用注入。这个时候,如果我们的web端是用的SpringMVC,这个时候,controller理论上是通过SpringMVC去注入,但是,使用spring注入,同样是可行的。同理,service等层,使用SpringMVC配置的统一扫描装配也是可以的。所以,如果说只是为了使用spring的依赖注入,是大可不必将springMVC和spring同时使用的。他们完全可以分开!
但是,尽管SpringMVC和spring都可以进行自动装配扫描,值得注意的是:
spring(父容器)并不能直接访问SpringMVC(子容器)所注入的对象,但是SpringMVC却可以访问到spring装载的对象。所以,在配置自动装配的时候,应该注意到这一点。

5、线程安全和 不安全的理解?
多线程这块我在工作中也有涉及到,我对于线程安全不安全是这么理解的,我认为线程的安全与否与java类本身无关,也就是说不能说StringBuffer是线程安全的,stringBuilder是线程不安全的,或hashMap是线程不安全的,HashTable是线程安全的,这几个类本身是与线程无关的,只有当它处于多线程的环境当中时,才可能引发线程安全不安全的问题,StringBuffer与stringBuilder的线程安全与否取决于他的append方法前面有没有开启互斥锁,对于HashMap与HashTable的线程与否,主要取决于put方法前面有没有开启线程的互斥锁,(线程本身就自带互斥锁,只不过默认不开启,当看到synchronized时会开启互斥)。
通过我的工作经验,我感觉只要不让多个线程同时操作同一个对象,一般不会涉及到线程不安全这种问题,只有到多个线程同时操作同一个对象的时候才有可能引发线程安全问题。
6、IOC的理解?
Spring 是完全面向接口的设计,降低程序耦合性(为什么),主要是事务控制并创建bean实例对象。在ssh整合时,充当黏合剂的作用。IOC(Inversion of Control) 控制反转/依赖注入,又称DI(Dependency Injection) (依赖注入) 从架构来讲默认 注入组件都是单例,有效降低java 吃内存的问题。Spring大大降低了 java 语言开发相互的内存。这是项目中使用spring的 主要原因。
IOC的作用:产生对象实例,所以它是基于工厂设计模式的
Spring IOC的注入
   通过属性进行注入,通过构造函数进行注入,工厂注入
Spring IOC 自动绑定模式:
可以设置autowire按以下方式进行绑定
按byType只要类型一致会自动寻找,
按byName自动按属性名称进行自动查找匹配.

7、AOP的理解?
AOP 面向方面(切面)编程
AOP是OOP的延续,是Aspect Oriented Programming的缩写,意思是面向方面(切面)编程。(为啥是OOP的延续) 注:OOP(Object-Oriented Programming ) 面向对象编程
AOP 主要应用于日志记录,性能统计,安全控制,事务处理(项目中使用的)等方面。
Spring中实现AOP技术:
在Spring中可以通过代理模式来实现AOP代理模式分为:
静态代理:一个接口,分别有一个真实实现和一个代理实现。(代码 缺点)
动态代理:通过代理类的代理,接口和实现类之间可以不直接发生联系,而可以在运行期(Runtime)实现动态关联。(优点)。动态代理有两种实现方式,可以通过jdk的动态代理实现也可以通过cglib 来实现而AOP默认是通过jdk的动态代理来实现的。jdk的动态代理必须要有接口的支持,而cglib不需要,它是基于类的。
概念解释:
切面(Aspect): 有切点(PointCut)和通知(Advice)组成,它既包括横切逻辑的定义,也包括了连接点的定义。
切点(Pointcut):一个切点定位多个类中的多个方法。
通知也叫增强(Advice):由方位和横切逻辑构成,所谓的方位指的是前置通知,后置通知,返回后通知,环绕通知,抛出异常后通知
连接点(JoinPoint):由切点和方位构成,用来描述在在哪些类的指定方法之前或之后执行
所谓的方位包括:
前置通知(Before advice):在连接点(join point)之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)。
返回后通知(After returning advice): 在连接点(join point)正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。
抛出异常后通知(After throwing advice):在方法抛出异常退出时执行的通知。
后置通知(After (finally) advice):当连接点退出的时候执行的通知(不论是正常返回还是异常退出)。
环绕通知(Around Advice):包围一个连接点(join point)的通知,如方法调用。这是最强大的一种通知类型。环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行

8、设计模式:单例模式
单例模式开始
Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例、饿汉式单例、登记式单例。

单例模式有以下特点:
  1、单例类只能有一个实例。
  2、单例类必须自己创建自己的唯一实例。
  3、单例类必须给所有其他对象提供这一实例。

单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、
缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。这些应用都或多或少具有资源管
理器的功能。每台计算机可以有若干个打印机,但只能有一个Printer Spooler,以避免两个打印作业同时输
出到打印机中。每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时
被两个请求同时调用。总之,选择单例模式就是为了避免不一致状态,避免政出多头。

//懒汉式单例类.在第一次调用的时候实例化自己   
public class Singleton {  
private Singleton() {}  
private static Singleton single=null;  
//静态工厂方法   
public static Singleton getInstance() {  
     if (single == null) {    
         single = new Singleton();  
     }
    return single;
}

//饿汉式单例类.在类初始化时,已经自行实例化   
public class Singleton1 {  
private Singleton1() {}  
private static final Singleton1 single = new Singleton1();  
//静态工厂方法   
public static Singleton1 getInstance() {  
         return single;  
    }  
}  

9、代理模式:
代理分为静态代理和动态代理
静态代理:
一个接口对应一个实现类和一个代理实现类,让代理实现类去做实现类想做的事。
动态代理:
一个接口只有一个实现类,没有代理实现类,在项目运行时,动态创建一个代理类来代替实现类去做某事。
代理模式中的角色:
* 1. 抽象角色 (接口)
* 2. 真实角色 真正的执行方法所在的类
* 3. 代理角色 代理真实角色的类
阐述动态代理模式:
答:Spring AOP 基于代理设计模式(基于jdk 的动态代理)
所谓代理设计模式:在代理模式中有个接口,接口中有个代理实现,要用代理实现去代表真实实现
10、工厂设计模式:
1. 简单工厂模式
2. 工厂方法模式
3. 抽象工厂模式
好处:
不用考虑实例化对象的细节 ,spring的 ioc/di (控制反转/依赖注入)就是使用工厂设计模式实现的。

考试题:阐述工厂设计模式?
	答:使用工程设计模式可以无需关注创建bean实例的细节,
		     所有细节就交于工厂处理,而调用者只需要下发指令即可。	

Springmvc
1、SpringMVC框架
springMVC是一个基于注解型的MVC框架。它的核心控制器是dispatcherServlet,在web.xml中配置。用户发起的请求都会被核心控制器拦截,进入springMVC的核心配置文件spring-servlet.xml。在这个xml中,主要配置的是注解的开启和扫描信息。首先要开启注解模式,annotation-driven。并且指定注解所在的路径,通过component-scan标签的base-package来设置。当请求到达后,springMVC会根据请求的action名称,通过ActionMapping去找到对应的action类中的requestMapping注解,这个注解中有一个value值,需要与请求的名称保持一致。所以请求可以到达action层。当然,springMVC也有自己的拦截器Interceptor。如果需要完成自定义拦截器,则需要写一个类,去继承handlerInterceptor类。重写里面的preHandler方法,在这方法中,通过返回true或者fasle来决定请求继续执行还是被拦截。定义好拦截器类以后,需要将拦截器配置到spring-servlet中去。springMVC中,获得参数的方式很简单,只需要在方法的参数列表中定义相关的局部变量就可以了。也可以通过requestParam的注解对参数进行更具体的配置,比如require为true时,要求这个参数必须传递。如果要求传递而没有传值,则报403错误。除了这样的配置以外,requestMapping也有相关的属性配置,比如requestType可以设置成GET或者是POST,指定请求的格式必须是Get请求还是post请求。如果需要传递的是对象类型参数,直接在参数列表中定义相关的对象,页面的参数名称必须要和类型的属性保持一致。(与strust2的传值方式稍微不同,没有对象.属性的方式)action接收参数后,则调用service业务逻辑层,完成业务操作。最后,springMVC进行页面跳转时,也很灵活,可以通过string返回一个字符串,也可以通过ModelAndView来进行跳转。ModelAndView中有一个setViewName方法,可以指定跳转的路径,还有一个addObject方法,可以将对象或者集合带到页面进行数据展示。如果是通过string类型跳转,则可以通过request.setAttribute()方法往页面传参。获得request的方式可以直接在参数列表中定义request对象获得,当然response也一样。
在spring-servlet中定义了一个试图解析器,统一配置了跳转路径的前缀和后缀名。
注意:可能会被问到的问题
1、常用的注解
2、拦截器的使用
2、SpringMVC的运行原理?
整个处理过程从一个HTTP请求开始:
1.Tomcat在启动时加载解析web.xml,找到spring mvc的前端总控制器DispatcherServlet,并且通过DispatcherServlet来加载相关的配置文件信息。
2.DispatcherServlet接收到客户端请求,找到对应HandlerMapping,根据映射规则,找到对应的处理器(Handler)。
3.调用相应处理器中的处理方法,处理该请求后,会返回一个ModelAndView。
4.DispatcherServlet根据得到的ModelAndView中的视图对象,找到一个合适的ViewResolver(视图解析器),根据视图解析器的配置,DispatcherServlet将要显示的数据传给对应的视图,最后显示给用户。

3、spring mvc的优点?
1.它是基于组件技术的.全部的应用对象,无论控制器和视图,还是业务对象之类的都是?java组件.并且和Spring提供的其他基础结构紧密集成.
2.不依赖于Servlet API(目标虽是如此,但是在实现的时候确实是依赖于Servlet的)
3.可以任意使用各种视图技术,而不仅仅局限于JSP
4.支持各种请求资源的映射策略
5.它应是易于扩展的
4、Springmvc的传参方式,批量接收的写法

/**

  • 第一种传值方式

  • @param id

  • @return http://localhost:8080/UserApplication/test2/100
    /
    @RequestMapping(value = “/test2/{id}”, method = RequestMethod.GET)
    public String test2(@PathVariable(“id”) Integer id) {
    return “id:” + id;
    }
    /
    *

  • 第二种传值方式

  • @param id

  • @return http://localhost:8080/UserApplication/test3?id=100

  • 设置默认值 这个是传参

  • 当他为false 时 使用这个注解可以不传这个参数 true时必须传 required默认值是true
    */
    @RequestMapping(value = “/test3”, method = RequestMethod.GET)
    // public String test3(@RequestParam(“id”) Integer id) {
    public String test3(@RequestParam(value = “id”, required = false, defaultValue = “0”) Integer id) {
    return “id:” + id;
    }
    5、Springmvc 对日期的处理,和附件的操作。
    日期的处理:在做web开发的时候,页面传入的都是String类型,SpringMVC可以对一些基本的类型进行转换,但是对于日期类的转换可能就需要我们配
    1、如果查询类使我们自己写,那么在属性前面加上@DateTimeFormat(pattern = “yyyy-MM-dd”),即可将String转换为Date类型,如下@DateTimeFormat(pattern = “yyyy-MM-dd”) private Date createTime;
    2、如果我们只负责web层的开发,就需要在controller中加入数据绑定:
    @InitBinder
    public void initBinder(WebDataBinder binder) {
    SimpleDateFormat dateFormat = new SimpleDateFormat(“yyyy-MM-dd”);
    dateFormat.setLenient(false);
    binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true)); //true:允许输入空值,false:不能为空值
    }
    3、可以在系统中加入一个全局类型转换器
    public class DateConverter implements Converter<String, Date> {
    @Override
    public Date convert(String source) {
    SimpleDateFormat dateFormat = new SimpleDateFormat(“yyyy-MM-dd”);
    dateFormat.setLenient(false);
    try {
    return dateFormat.parse(source);
    } catch (ParseException e) {
    e.printStackTrace();
    }
    return null;
    }
    <bean`id="conversionnService"class=“org.springframework.format.support.FormattingConversionServiceFactoryBean”>






    <mvc:annotation-driven conversion-service=“conversionService” />
    4、如果将日期类型转换为String在页面上显示,需要配合一些前端的技巧进行处理。
    5、SpringMVC使用@ResponseBody返回json时,日期格式默认显示为时间戳。
    @Component(“customObjectMapper”)
    public class CustomObjectMapper extends ObjectMapper {

      public CustomObjectMapper() {  
      CustomSerializerFactory factory = new CustomSerializerFactory();  
      factory.addGenericMapping(Date.class, new JsonSerializer<Date>() {  
          @Override  
          public void serialize(Date value, JsonGenerator jsonGenerator,  
      	    SerializerProvider provider) throws IOException, JsonProcessingException {  
      	SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
      	jsonGenerator.writeString(sdf.format(value));  
          }  
      });  
      this.setSerializerFactory(factory);  
      }  
    

    }
    mvc:annotation-driven
    mvc:message-converters



    </mvc:message-converters>
    </mvc:annotation-driven>
    6、date类型转换为json字符串时,返回的是long time值,
    如果需要返回指定的日期的类型的get方法上写上@JsonFormat(pattern=“yyyy-MM-dd HH:mm:ss”,timezone = “GMT+8”) ,即可将json返回的对象为指定的类型。
    @DateTimeFormat(pattern=“yyyy-MM-dd HH:mm:ss”)
    @JsonFormat(pattern=“yyyy-MM-dd HH:mm:ss”,timezone = “GMT+8”)
    public Date getCreateTime() {
    return this.createTime;
    }
    6、Springmvc 的常用注解?
    1、@RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
    2、@PathVariable 用于将请求URL中的模板变量映射到功能处理方法的参数上,即取出uri模板中的变量作为参数。
    3、@ModelAttribute和 @SessionAttributes
    代表的是:该Controller的所有方法在调用前,先执行此@ModelAttribute方法,可用于注解和方法参数中,可以把这个@ModelAttribute特性,应用在BaseController当中,所有的Controller继承BaseController,即可实现在调用Controller时,先执行@ModelAttribute方法。
    @SessionAttributes即将值放到session作用域中,写在class上面。
    具体示例参见下面:使用 @ModelAttribute 和 @SessionAttributes 传递和保存数据
    4、@requestParam主要用于在SpringMVC后台控制层获取参数,类似一种是request.getParameter(“name”),它有三个常用参数:defaultValue = “0”, required = false, value = “isApp”;defaultValue 表示设置默认值,required 铜过boolean设置是否是必须要传入的参数,value 值表示接受的传入的参数类型。
    5、@ResponseBody 作用: 该注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区。
    使用时机:返回的数据不是html标签的页面,而是其他某种格式的数据时(如json、xml等)使用;
    7、Springmvc 的拦截器配置步骤?(了解)
    1.首先在spring-mvc.xml文件中添加拦截器配置

<mvc:interceptors>
	<mvc:interceptor>
		<mvc:mapping path="/**" />
		<!-- 指向自定义拦截器类 -->
		<bean class="com.jk.interceptors.SecurityInterceptor">
			<!-- 不需要权限验证的地址 -->
			<property name="excludeUrls">
				<list>
					<value>/loginController/verifyCheck</value><!-- 验证码校验 --
				</list>
			</property>
		</bean>
	</mvc:interceptor>
</mvc:interceptors>

2.创建自定义拦截器类实现HandlerInterceptor接口重写preHandle方法
该方法会在Controller的方法执行前会被调用,可以使用这个方法来中断或者继续执行链的处理
当返回true时,处理执行链会继续,当返回false时,则不会去执行Controller的方法。
public class SecurityInterceptor implements HandlerInterceptor {
//日志记录
private static final Logger logger = Logger.getLogger(SecurityInterceptor.class);
private List excludeUrls;// 不需要拦截的资源
public List getExcludeUrls() {
return excludeUrls;
}
public void setExcludeUrls(List excludeUrls) {
this.excludeUrls = excludeUrls;
}
/**
* 完成页面的render后调用
/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object object, Exception exception) throws Exception {
}
/
*
* 在调用controller具体方法后拦截
/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object object, ModelAndView modelAndView) throws Exception {
}
/
*
* 在调用controller具体方法前拦截
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
String requestUri = request.getRequestURI();
String contextPath = request.getContextPath();
String servletPath = requestUri.substring(contextPath.length());
String url = StringUtils.substringBeforeLast(servletPath, “.”);
// logger.info(url);
if (url.indexOf("/baseController/") > -1 || excludeUrls.contains(url)) {// 如果要访问的资源是不需要验证的
return true;
}
Account account = (Account) request.getSession().getAttribute(“account”);
if (account == null || account.getId().equalsIgnoreCase("")) {// 如果没有登录或登录超时
request.setAttribute(“msg”, “您还没有登录或登录已超时,请重新登录,然后再刷新本功能!”);
request.getRequestDispatcher("/error/noSession.jsp").forward(request, response);
return false;
}

// if (!user.getResources().contains(url)) {// 如果当前用户没有访问此资源的权限
// request.setAttribute(“msg”, “您没有访问此资源的权限!
请联系超管赋予您
[” + url + “]
的资源访问权限!”);
// request.getRequestDispatcher("/error/noSecurity.jsp").forward(request, response);
// return false;
// }
return true;
}
}

三、JQuery 篇
1、jquery ( d o c u m e n t ) . r e a d y ( ) 与 w i n d o w . o n l o a d 的 区 别 J q u e r y 中 (document).ready() 与window.onload的区别 Jquery中 (document).ready()window.onloadJquery(document).ready()的作用类似于传统JavaScript中的window.onload方法,不过与window.onload方法还是有区别的。
1.执行时间

    window.onload必须等到页面内包括图片的所有元素加载完毕后才能执行。 
    $(document).ready()是DOM结构绘制完毕后就执行,不必等到加载完毕。 

2.编写个数不同

     window.onload不能同时编写多个,如果有多个window.onload方法,只会执行一个 
     $(document).ready()可以同时编写多个,并且都可以得到执行 

3.简化写法

     window.onload没有简化写法 
     $(document).ready(function(){})可以简写成$(function(){});

2、你知道jquery中的选择器吗,请简单介绍一下?
1、基本选择器
1、#id 用法: $("#myDiv"); 返回值 单个元素的组成的集合 说明: 这个就是直接选择html中的id=“myDiv”
2、Element 用法: $(“div”) 返回值 集合元素 说明: element的英文翻译过来是”元素”,所以element其实就是html已经定义的标签元素,例如div, input, a等等.
3、class 用法: $(".myClass") 返回值 集合元素 说明: 这个标签是直接选择html代码中class=“myClass"的元素或元素组(因为在同一html页面中 class是可以存在多个同样值的)
4、* 用法: $(”*") 返回值 集合元素 说明: 匹配所有元素,多用于结合上下文来搜索
5、selector1, selector2, selectorN 用法: $(“div,span,p.myClass”) 返回值 集合元素 说明: 将每一个选择器匹配到的元素合并后一起返回.你可以指定任意多个选择器, 并将匹配到的元素合 并到一个结果内。其中p.myClass是表示匹配元素 p class=“myClass”
2、层级选择器
1 、ancestor descendant 用法: $(“form input”) ; 返回值 集合元素 说明: 在给定的祖先元素下匹配所有后代元素.这个要和"arent > child"区分开。 祖先元素中查找,包含子元素和子元素的子元素。
2、parent > child
用法: $(“form > input”) ; 返回值 集合元素 说明: 在给定的父元素下匹配所有子元素。注意:要区分好后代元素与子元素 父元素中查找,只包含子元素,不包含子元素的子元素。
3、prev + next 用法: $(“label + input”) ; 返回值 集合元素 说明: 匹配所有紧接在 prev 元素后的 next 元素
4、prev ~ siblings 用法: $(“form ~ input”) ; 返回值 集合元素 说明: 匹配 prev 元素之后的所有 siblings 元素.注意:是匹配之后的元素,不包含该元素在内,并且JQuery的siblings方法匹配的是和prev同辈的元素,其后辈元素不被匹配. 注意: (“prev ~ div”) 选择器只能选择 "# prev"元素后面的同辈元素; 而 jQuery 中的方法 siblings() 与前后位置无关, 只要是同辈节点就可以选取

注意:《参考文档》https://blog.csdn.net/pseudonym_/article/details/76093261
3、jquery常用方法总结
(1)取值与赋值操作
$("#ID").val(); //取value值
$("#ID").val(“xxx”); //赋值
$("#ID").text(); //相当于取innerText
$("#ID").text(""); //相当于赋值给innerText
$("#ID").html(); //相当于取innerHTML
$("#ID").html(""); //相当于赋值给innerHTML

(2)属性设置
$("#ID").attr(key,value);//取得或设置匹配元素的属性值

(3)显示和隐藏
$("#ID").hide(); //隐藏
$("#ID").show(); //显示

(4)事件处理
$(document).ready(fn);
$("#ID").bind(type,[data],fn);//绑定事件处理器函数 $("#ID").toggle(fn,fn);//注册每次点击时切换要调用的函数

(5)外观效果
$("#ID").addClass(class);//添加样式
$("#ID").removeClass(class);//移除样式
$("#ID").css(name,value);//设置一个样式属性的值

(6)序列化
$(“form”).serialize();//序列化表格内容为字符串

(7)
4、JQuery 常用的事件
$(function (){}) 页面加载事件
click() 点击,单击事件
blur() 失去焦点事件
change() 内容改变事件
dblclick() 双击事件
focus() 获取焦点事件

5、请谈一下你对Ajax的认识
AJAX 全称: 异步JavaScript及 XML(Asynchronous JavaScript And XML)
Ajax的核心是JavaScript对象XmlHttpRequest(XHR)。
Ajax的优点 的优点:
    1.提高用户体验度(UE)
    2.提高应用程序的性能
    3.进行局部刷新

  1. AJAX不是一种新的编程语言,而是一种用于创建更好更快以及交互性更强的 Web 应用程序的技术。
    2.通过 AJAX,我们的 JavaScript 可使用JavaScript的XMLHttpRequest对象来直接与服务器进行通信。通过这个对象,我们的
    JavaScript 可在不重载页面的情况与Web服务器交换数据,即可局部刷新。
    3.AJAX 在浏览器与 Web 服务器之间使用异步数据传输(HTTP 请求),这样就可使网页从服务器请求少量的信息,而不是整个
    页面,减轻服务器的负担,提升站点的性能。
    4.AJAX 可使因特网应用程序更小、更快,更友好,用户体验(UE)好。
    5.Ajax是基于标准化并被广泛支持的技术,并且不需要插件和下载小程序
    Ajax包含下列技术:
    基于web标准(standards-basedpresentation)XHTML+CSS的表示;
    使用 DOM(Document ObjectModel)进行动态显示及交互;
    使用 XML 和 XSLT 进行数据交换及相关操作;
    使用 XMLHttpRequest 进行异步数据查询、检索;
    使用 JavaScript 将所有的东西绑定在一起。

6、ajax 三种使用方式
1. . a j a x ( ) 2. .ajax({}) 2. .ajax()2..get()
3.$.post()

7、ajax 常用属性
1.url:
要求为String类型的参数,(默认为当前页地址)发送请求的地址。
2.type:
要求为String类型的参数,请求方式(post或get)默认为get。注意其他http请求方法,例如put和delete也可以使用,但仅部分浏览器支持。
3.async:
要求为Boolean类型的参数,默认设置为true,所有请求均为异步请求。如果需要发送同步请求,请将此选项设置为false。注意,同步请求将锁住浏览器,用户其他操作必须等待请求完成才可以执行。
4.data:
要求为Object或String类型的参数,发送到服务器的数据。
5.dataType:
要求为String类型的参数,预期服务器返回的数据类型。如果不指定,JQuery将自动根据http包mime信息返回responseXML或responseText,并作为回调函数参数传递。可用的类型如下:
xml:返回XML文档,可用JQuery处理。
html:返回纯文本HTML信息;包含的script标签会在插入DOM时执行。
script:返回纯文本JavaScript代码。不会自动缓存结果。除非设置了cache参数。注意在远程请求时(不在同一个域下),所有post请求都将转为get请求。
json:返回JSON数据。
jsonp:JSONP格式。使用SONP形式调用函数时,例如myurl?callback=?,JQuery将自动替换后一个“?”为正确的函数名,以执行回调函数。
text:返回纯文本字符串。
6.success:要求为Function类型的参数,请求成功后调用的回调函数,有两个参数。
(1)由服务器返回,并根据dataType参数进行处理后的数据。
(2)描述状态的字符串。
function(data, textStatus){
//data可能是xmlDoc、jsonObj、html、text等等
this; //调用本次ajax请求时传递的options参数
}
7.error:
要求为Function类型的参数,请求失败时被调用的函数。该函数有3个参数,即XMLHttpRequest对象、错误信息、捕获的错误对象(可选)。ajax事件函数如下:
function(XMLHttpRequest, textStatus, errorThrown){
//通常情况下textStatus和errorThrown只有其中一个包含信息
this; //调用本次ajax请求时传递的options参数
}
8、Json
Json(JavaScript Object Notation)特点:
  json分为两种格式:

json对象(就是在{}中存储键值对,键和值之间用冒号分隔,
键 值 对之间用逗号分隔);

json数组(就是[]中存储多个json对象,json对象之间用逗号分隔)
(两者间可以进行相互嵌套)数据传输的载体之一
对象 转 json
页面的ajax
dataType:“json”, 规定 返回值是 json对象
Java中 调用
String jsonStr = JSON.toJSONString(对象);
获得 json字符串

第四个月SSM框架篇
一、基础篇

1、Map介绍,以及map的底层;list介绍,以及list底层
java.util 中的集合类包含 Java 中某些最常用的类。最常用的集合类是 List 和 Map。
List的实现类分别有ArrayList,LinkedList,Vector。
ArrayList:相当于是new了个Object的类型的数组,默认值是10,底层数据结构使数组结构,查询速度快,增删改慢。
LinkedList:底层使用链表结构,增删速度快,是根据地址传递的,两个之间有相互关联的地址:查询稍慢,删除新增快,LinkedList也有get()取值方法,但是它是从第一个查询完所有的之后,在从中用get()取值。
Vector:底层是数组结构,线程同步ArrayList是线程不同步;
ArrayList当初始化容量超过10时,会重新new一个相当于之前150%的集合 ,把原来的东西放入这150%中;Vector:当容量超过10时,则会new一个200%的集合放进去,浪费内存。
CopyOnWriteArrayList:在写时拷贝,也就是如果需要对CopyOnWriteArrayList的内容进行改变,首先会拷贝一份新的List并且在新的List上进行修改,最后将原List的引用指向新的List。使用CopyOnWriteArrayList可以线程安全地遍历,因为如果另外一个线程在遍历的时候修改List的话,实际上会拷贝出一个新的List上修改,而不影响当前正在被遍历的List。

Map 提供了一个更通用的元素存储方法。Map 集合类用于存储元素对(称作“键”和“值”),其中每个键映射到一个值。从概念上而言,您可以将 List 看作是具有数值键的 Map。而实际上,除了 List 和 Map 都在定义 java.util 中外,两者并没有直接的联系。
HashMap底层就是一个数组结构,数组中的每一项又是一个链表。当新建一个HashMap的时候,就会初始化一个数组。
Entry就是数组中的元素,每个Entry其实就是一个key-value对,它持有一个指向下一个元素的引用,这就构成了链表。
HashMap在底层将key-value当成一个整体进行处理,这个整体就是一个Entry对象。HashMap底层采用一个Entry[]数组来保存所有的key-value对,当需要存储一个Entry对象时,会根据hash算法来决定其在数组中的存储位置,再根据equals方法决定其在该数组位置上的链表中的存储位置;当需要取出一个Entry时,也会根据hash算法找到其在数组中的存储位置,再根据equals方法从该位置上的链表中取出该Entry。

默认是构建一个初始容量为16,负载因子为0.75的HashMap。也就是说,默认情况下,数组大小为16,那么当HashMap中元素个数超过160.75=12的时候,就把数组的大小扩展为 216=32,即扩大一倍,然后重新计算每个元素在数组中的位置,而这是一个非常消耗性能的操作,所以如果我们已经预知HashMap中元素的个数,那么预设元素的个数能够有效的提高HashMap的性能。
HashTable与HashMap大体一致,但是在操作HashTable时会默认加上一个同步锁,其它进程要操作此对象。只能等本次操作完成后解开同步锁。
ConcurrentHashMap遵从了和Hashtable一样的规范,这里指的是线程安全的规范,但是其底层的实现与Hashtable并不一致。ConcurrentHashMap底层采用的锁机制,执行put方法的线程会获得锁,只有当此线程的put方法执行结束后才会释放锁,根据多线程的知识,获得锁的线程会通知其他试图操作put方法的线程,并通知其他线程出于等待状态,直到释放锁后,其他线程才会去重新竞争锁。这一点保证了ConcurrentHashMap的线程安全。
HashMap采用链地址法解决哈希冲突,多线程访问哈希表的位置并修改映射关系的时候,后执行的线程会覆盖先执行线程的修改,所以不是线程安全的。
Hashtable采用synchronized关键字解决了并发访问的安全性问题但是效率较低。
ConcurrentHashMap其实是HashTable的升级版,使用了线程锁分段技术,每次访问只允许一个线程修改哈希表的映射关系,所以是线程安全的。
2、接口和抽象类有什么区别?或者问你选择使用接口和抽象类的依据是什么?
接口和抽象类的概念不一样。接口是对动作的抽象,抽象类是对根源的抽象。
抽象类表示的是,这个对象是什么。接口表示的是,这个对象能做什么。比如,男人,女人,这两个类(如果是类的话……),他们的抽象类是人。说明,他们都是人。
人可以吃东西,狗也可以吃东西,你可以把“吃东西”定义成一个接口,然后让这些类去实现它.
所以,在高级语言上,一个类只能继承一个类(抽象类)(正如人不可能同时是生物和非生物),但是可以实现多个接口(吃饭接口、走路接口)。
第一点. 接口是抽象类的变体,接口中所有的方法都是抽象的。而抽象类是声明方法的存在而不去实现它的类。
第二点. 接口可以多继承,抽象类不行
第三点. 接口定义方法,不能实现,而抽象类可以实现部分方法。
第四点. 接口中基本数据类型为static 而抽类象不是的。
当你关注一个事物的本质的时候,用抽象类;当你关注一个操作的时候,用接口。
抽象类的功能要远超过接口,但是,定义抽象类的代价高。因为高级语言来说(从实际设计上来说也是)每个类只能继承一个类。在这个类中,你必须继承或编写出其所有子类的
所有共性。虽然接口在功能上会弱化许多,但是它只是针对一个动作的描述。而且你可以在一个类中同时实现多个接口。在设计阶段会降低难度的。
3、乐观锁和悲观锁的区别?(最全面的分析)
悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。
乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。
两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下,即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果经常产生冲突,上层应用会不断的进行retry,这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适。
以下为了解部分:
本质上,数据库的乐观锁做法和悲观锁做法主要就是解决下面假设的场景,避免丢失更新问题:
一个比较清楚的场景
下面这个假设的实际场景可以比较清楚的帮助我们理解这个问题:
假设当当网上用户下单买了本书,这时数据库中有条订单号为001的订单,其中有个status字段是’有效’,表示该订单是有效的;
后台管理人员查询到这条001的订单,并且看到状态是有效的
用户发现下单的时候下错了,于是撤销订单,假设运行这样一条SQL: update order_table set status = ‘取消’ where order_id = 001;
后台管理人员由于在b这步看到状态有效的,这时,虽然用户在c这步已经撤销了订单,可是管理人员并未刷新界面,看到的订单状态还是有效的,于是点击”发货”按钮,将该订单发到物流部门,同时运行类似如下SQL,将订单状态改成已发货:update order_table set status = ‘已发货’ where order_id = 001
观点1:只有冲突非常严重的系统才需要悲观锁;“所有悲观锁的做法都适合于状态被修改的概率比较高的情况,具体是否合适则需要根据实际情况判断。”,表达的也是这个意思,不过说法不够准确;的确,之所以用悲观锁就是因为两个用户更新同一条数据的概率高,也就是冲突比较严重的情况下,所以才用悲观锁。

观点2:最后提交前作一次select for update检查,然后再提交update也是一种乐观锁的做法,的确,这符合传统乐观锁的做法,就是到最后再去检查。但是wiki在解释悲观锁的做法的时候,’It is not appropriate for use in web application development.’, 现在已经很少有悲观锁的做法了,所以我自己将这种二次检查的做法也归为悲观锁的变种,因为这在所有乐观锁里面,做法和悲观锁是最接近的,都是先select for update,然后update
在实际应用中我们在更新数据的时候,更严谨的做法是带上更新前的“状态”,如
update order_table set status = ‘取消’ where order_id = 001 and status = ‘待支付’ and …;
update order_table set status = ‘已发货’ where order_id = 001 and status = ‘已支付’ and …;
然后在业务逻辑代码里判断更新的记录数,为0说明数据库已经被更新了,否则是正常的。

二、框架篇
一、SpringMVC
1、springmvc框架
springMVC是一个基于注解型的MVC框架。它的核心控制器是dispatcherServlet,在web.xml中配置。用户发起的请求都会被核心控制器拦截,进入springMVC的核心配置文件spring-servlet.xml。在这个xml中,主要配置的是注解的开启和扫描信息。首先要开启注解模式,annotation-driven。并且指定注解所在的路径,通过component-scan标签的base-package来设置。当请求到达后,springMVC会根据请求的action名称,通过ActionMapping去找到对应的action类中的requestMapping注解,这个注解中有一个value值,需要与请求的名称保持一致。所以请求可以到达action层。当然,springMVC也有自己的拦截器Interceptor。如果需要完成自定义拦截器,则需要写一个类,去继承handlerInterceptor类。重写里面的preHandler方法,在这方法中,通过返回true或者fasle来决定请求继续执行还是被拦截。定义好拦截器类以后,需要将拦截器配置到spring-servlet中去。springMVC中,获得参数的方式很简单,只需要在方法的参数列表中定义相关的局部变量就可以了。也可以通过requestParam的注解对参数进行更具体的配置,比如require为true时,要求这个参数必须传递。如果要求传递而没有传值,则报403错误。除了这样的配置以外,requestMapping也有相关的属性配置,比如requestType可以设置成GET或者是POST,指定请求的格式必须是Get请求还是post请求。如果需要传递的是对象类型参数,直接在参数列表中定义相关的对象,页面的参数名称必须要和类型的属性保持一致。(与strust2的传值方式稍微不同,没有对象.属性的方式)action接收参数后,则调用service业务逻辑层,完成业务操作。最后,springMVC进行页面跳转时,也很灵活,可以通过string返回一个字符串,也可以通过ModelAndView来进行跳转。ModelAndView中有一个setViewName方法,可以指定跳转的路径,还有一个addObject方法,可以将对象或者集合带到页面进行数据展示。如果是通过string类型跳转,则可以通过request.setAttribute()方法往页面传参。获得request的方式可以直接在参数列表中定义request对象获得,当然response也一样。
在spring-servlet中定义了一个试图解析器,统一配置了跳转路径的前缀和后缀名。
注意:可能会被问到的问题
1、常用的注解
2、拦截器的使用
2、SpringMvc整合
1.首先,要在web.xml里面配置SpringMVC的核心控制器,DispatcherServlet,对指定的后缀请求进行拦截。
2.Controller层要加 @Controller注解,表明该类是MVC的控制层。
3.创建Service接口,给实现类加上注解 @Component或者 @Service 表明这是Service业务处理层
4.在Controller层声明Service变量(属性),给变量(属性) 加上 @Autowired注解,通过自动绑定机制将Service注入到Controller。 (注:@Autowired默认是ByType,如果想根据属性名注入,那么就再加上注解 @Resource(name=“属性名”))
5.在Controller层的方法上加上注解 @RequestMapping(“requestAddress”) 表明该方法的请求地址
6.Dao层要加上注解 @Repository 表明这是数据库持久层
7.同样将dao实例注入到service层中。
8.配置视图解析器 “InternalResourceViewResolver”,对处理后的跳转进行统一配置。
3、SpringMVC的常用注解
1、@RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
2、@PathVariable 用于将请求URL中的模板变量映射到功能处理方法的参数上,即取出uri模板中的变量作为参数。
3、@ModelAttribute和 @SessionAttributes
代表的是:该Controller的所有方法在调用前,先执行此@ModelAttribute方法,可用于注解和方法参数中,可以把这个@ModelAttribute特性,应用在BaseController当中,所有的Controller继承BaseController,即可实现在调用Controller时,先执行@ModelAttribute方法。
@SessionAttributes即将值放到session作用域中,写在class上面。
具体示例参见下面:使用 @ModelAttribute 和 @SessionAttributes 传递和保存数据
4、@requestParam主要用于在SpringMVC后台控制层获取参数,类似一种是request.getParameter(“name”),它有三个常用参数:defaultValue = “0”, required = false, value = “isApp”;defaultValue 表示设置默认值,required 铜过boolean设置是否是必须要传入的参数,value 值表示接受的传入的参数类型。
5、@ResponseBody 作用: 该注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区。
使用时机:返回的数据不是html标签的页面,而是其他某种格式的数据时(如json、xml等)使用;
二、Spring
1、请解释Spring Bean的生命周期?(了解)
Spring Bean的生命周期简单易懂。在一个bean实例被初始化时,需要执行一系列的初始化操作以达到可用的状态。同样的,当一个bean不在被调用时需要进行相关的析构操作,并从bean容器中移除。
Spring bean factory 负责管理在spring容器中被创建的bean的生命周期。Bean的生命周期由两组回调(call back)方法组成。
初始化之后调用的回调方法。
销毁之前调用的回调方法。
Spring框架提供了以下四种方式来管理bean的生命周期事件:
nitializingBean和DisposableBean回调接口
针对特殊行为的其他Aware接口
Bean配置文件中的Custom init()方法和destroy()方法
@PostConstruct和@PreDestroy注解方式
2、Spring Bean的作用域之间有什么区别?
Spring容器中的bean可以分为5个范围。
1.singleton:这种bean范围是默认的,这种范围确保不管接受到多少个请求,每个容器中只有一个bean的实例,单例的模式由bean factory自身来维护。
2. prototype:原形范围与单例范围相反,为每一个bean请求提供一个实例。
3. request:在请求bean范围内会每一个来自客户端的网络请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收。
4. Session:与请求范围类似,确保每个session中有一个bean的实例,在session过期后,bean会随之失效。
5. global-session:global-session和Portlet应用相关。当你的应用部署在Portlet容器中工作时,它包含很多portlet。如果你想要声明让所有的portlet共用全局的存储变量的话,那么这全局变量需要存储在global-session中。
3、Spring如何解决并发访问的线程安全性问题?
springmvc的controller是singleton的(非线程安全的),这也许就是他和struts2的区别吧!和Struts一样,Spring的Controller默认是Singleton的,这意味着每个request过来,系统都会用原有的instance去处理,这样导致了两个结果:一是我们不用每次创建Controller,二是减少了对象创建和垃圾收集的时间;由于只有一个Controller的instance,当多个线程调用它的时候,它里面的instance变量就不是线程安全的了,会发生窜数据的问题。当然大多数情况下,我们根本不需要考虑线程安全的问题,比如dao,service等,除非在bean中声明了实例变量。因此,我们在使用spring mvc 的contrller时,应避免在controller中定义实例变量。
如果控制器是使用单例形式,且controller中有一个私有的变量a,所有请求到同一个controller时,使用的a变量是共用的,即若是某个请求中修改了这个变量a,则,在别的请求中能够读到这个修改的内容。。
有几种解决方法:
1、在Controller中使用ThreadLocal变量
2、在spring配置文件Controller中声明 scope=“prototype”,每次都创建新的controller
所在在使用spring开发web 时要注意,默认Controller、Dao、Service都是单例的。
ThreadLocal 使用范例:
ThreadLocalstartTime = newThreadLocal(); 定义一个ThreadLocal 变量
startTime.set(System.currentTimeMillis()); 写入值
startTime.get(); 读取值
4、ThreadLocal和线程同步机制相比有什么优势呢?
ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。
在同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,使用同步机制要求程序慎密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂的问题,程序设计和编写难度相对较大。
而ThreadLocal则从另一个角度来解决多线程的并发访问。ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。
概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。
5、Spring事务隔离级别和传播特性
一、Propagation (事务的传播属性)
Propagation :key属性确定代理应该给哪个方法增加事务行为。这样的属性最重要 的部份是传播行为。有以下选项可供使用:PROPAGATION_REQUIRED–支持当前事务, 如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_SUPPORTS–支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY–支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW–新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED–以非事务方式执行操作,如果当前存在事务,就把当 前事务挂起。
PROPAGATION_NEVER–以非事务方式执行,如果当前存在事务,则抛出异常。
1: PROPAGATION_REQUIRED
加入当前正要执行的事务不在另外一个事务里,那么就起一个新的事务
比如说,ServiceB.methodB的事务级别定义为PROPAGATION_REQUIRED, 那么由于 执行ServiceA.methodA的时候,
ServiceA.methodA已经起了事务,这时调用ServiceB.methodB,ServiceB.methodB 看到自己已经运行在ServiceA.methodA
的事务内部,就不再起新的事务。而假如ServiceA.methodA运行的时候发现自己没 有在事务中,他就会为自己分配一个事务。
这样,在ServiceA.methodA或者在ServiceB.methodB内的任何地方出现异常,事务 都会被回滚。即使ServiceB.methodB的事务已经被
提交,但是ServiceA.methodA在接下来fail要回滚,ServiceB.methodB也要回滚
2:PROPAGATION_SUPPORTS
如果当前在事务中,即以事务的形式运行,如果当前不再一个事务中,那么就以非 事务的形式运行
3:PROPAGATION_MANDATORY
必须在一个事务中运行。也就是说,他只能被一个父事务调用。否则,他就要抛出 异常
4:PROPAGATION_REQUIRES_NEW
这个就比较绕口了。 比如我们设计ServiceA.methodA的事务级别为 PROPAGATION_REQUIRED,ServiceB.methodB的事务级别为 ROPAGATION_REQUIRES_NEW,
那么当执行到ServiceB.methodB的时候,ServiceA.methodA所在的事务就会挂起, ServiceB.methodB会起一个新的事务,等待ServiceB.methodB的事务完成以后,
他才继续执行。他与PROPAGATION_REQUIRED 的事务区别在于事务的回滚程度了。 因为ServiceB.methodB是新起一个事务,那么就是存在
两个不同的事务。如果ServiceB.methodB已经提交,那么ServiceA.methodA失败回 滚,ServiceB.methodB是不会回滚的。如果ServiceB.methodB失败回滚,
如果他抛出的异常被ServiceA.methodA捕获,ServiceA.methodA事务仍然可能提交。
5: PROPAGATION_NOT_SUPPORTED
当前不支持事务。比如ServiceA.methodA的事务级别是PROPAGATION_REQUIRED , 而ServiceB.methodB的事务级别是PROPAGATION_NOT_SUPPORTED ,
那么当执行到ServiceB.methodB时,ServiceA.methodA的事务挂起,而他以非事务 的状态运行完,再继续ServiceA.methodA的事务。
6: PROPAGATION_NEVER
不能在事务中运行。假设ServiceA.methodA的事务级别是PROPAGATION_REQUIRED, 而ServiceB.methodB的事务级别是PROPAGATION_NEVER ,
那么ServiceB.methodB就要抛出异常了。
7: PROPAGATION_NESTED
理解Nested的关键是savepoint。他与PROPAGATION_REQUIRES_NEW的区别是, PROPAGATION_REQUIRES_NEW另起一个事务,将会与他的父事务相互独立,
而Nested的事务和他的父事务是相依的,他的提交是要等和他的父事务一块提交 的。也就是说,如果父事务最后回滚,他也要回滚的。
而Nested事务的好处是他有一个savepoint。
***列子
ServiceA {
/

* 事务属性配置为 PROPAGATION_REQUIRED
*/
void methodA() {
try {
//savepoint
ServiceB.methodB(); //PROPAGATION_NESTED 级别
} catch (SomeException) {
// 执行其他业务, 如 ServiceC.methodC();
}
}
********************************************
也就是说ServiceB.methodB失败回滚,那么ServiceA.methodA也会回滚到savepoint点 上,ServiceA.methodA可以选择另外一个分支,比如
ServiceC.methodC,继续执行,来尝试完成自己的事务。
但是这个事务并没有在EJB标准中定义。
二.Spring事务的隔离级别
1. ISOLATION_DEFAULT: 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.另外四个与JDBC的隔离级别相对应
2. ISOLATION_READ_UNCOMMITTED: 这是事务最低的隔离级别,它充许令外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。
3. ISOLATION_READ_COMMITTED: 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据
4. ISOLATION_REPEATABLE_READ: 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。
5. ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻像读。
6、什么是脏数据,脏读不可重复读,幻觉读?
脏读: 指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提 交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。因为这 个数据是还没有提交的数据,那么另外一个事务读到的这个数据是脏数据,依据脏数据 所做的操作可能是不正确的。
不可重复读: 指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。
幻觉读: 指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。
三、mybatis
1、在mybatis中,#{}和${}的区别是什么

  1. #将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。如:order by #user_id#,如果传入的值是111,那么解析成sql时的值为order by “111”, 如果传入的值是id,则解析成的sql为order by “id”.
  2. $将传入的数据直接显示生成在sql中。如:order by u s e r i d user_id userid,如果传入的值是111,那么解析成sql时的值为order by user_id, 如果传入的值是id,则解析成的sql为order by id.
  3. #方式能够很大程度防止sql注入。 
    4. 方 式 无 法 防 止 S q l 注 入 。 5. 方式无法防止Sql注入。 5. Sql5.方式一般用于传入数据库对象,例如传入表名. 
    6.一般能用#的就别用 . M y B a t i s 排 序 时 使 用 o r d e r b y 动 态 参 数 时 需 要 注 意 , 用 . MyBatis排序时使用order by 动态参数时需要注意,用 .MyBatis使orderby而不是#
    2、Xml映射文件中,除了常见的select|insert|updae|delete标签之外,还有哪些标签?(京东面试题)
    答:还有很多其他的标签,、、、、,加上动态sql的9个标签,trim|where|set|foreach|if|choose|when|otherwise|bind等,其中为sql片段标签,通过标签引入sql片段,为不支持自增的主键生成策略标签。
    3、最佳实践中,通常一个Xml映射文件,都会写一个Dao接口与之对应,请问,这个Dao接口的工作原理是什么?Dao接口里的方法,参数不同时,方法能重载吗?(京东面试题)
    答:Dao接口,就是人们常说的Mapper接口,接口的全限名,就是映射文件中的namespace的值,接口的方法名,就是映射文件中MappedStatement的id值,接口方法内的参数,就是传递给sql的参数。Mapper接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为key值,可唯一定位一个MappedStatement,举例:com.mybatis3.mappers.StudentDao.findStudentById,可以唯一找到namespace为com.mybatis3.mappers.StudentDao下面id = findStudentById的MappedStatement。在Mybatis中,每一个、、、标签,都会被解析为一个MappedStatement对象。
    Dao接口里的方法,是不能重载的,因为是全限名+方法名的保存和寻找策略。
    Dao接口的工作原理是JDK动态代理,Mybatis运行时会使用JDK动态代理为Dao接口生成代理proxy对象,代理对象proxy会拦截接口方法,转而执行MappedStatement所代表的sql,然后将sql执行结果返回。
    4、Mybatis动态sql是做什么的?都有哪些动态sql?能简述一下动态sql的执行原理不?
    答:Mybatis动态sql可以让我们在Xml映射文件内,以标签的形式编写动态sql,完成逻辑判断和动态拼接sql的功能,Mybatis提供了9种动态sql标签trim|where|set|foreach|if|choose|when|otherwise|bind。
    其执行原理为,使用OGNL从sql参数对象中计算表达式的值,根据表达式的值动态拼接sql,以此来完成动态sql的功能。
    5、Mybatis是否支持延迟加载?如果支持,它的实现原理是什么?
    Mybatis仅支持association关联对象和collection关联集合对象的延迟加载,association指的就是一对一,collection指的就是一对多查询。在Mybatis配置文件中,可以配置是否启用延迟加载lazyLoadingEnabled=true|false。
    它的原理是,使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用a.getB().getName(),拦截器invoke()方法发现a.getB()是null值,那么就会单独发送事先保存好的查询关联B对象的sql,把B查询上来,然后调用a.setB(b),于是a的对象b属性就有值了,接着完成a.getB().getName()方法的调用。这就是延迟加载的基本原理。
    当然了,不光是Mybatis,几乎所有的包括Hibernate,支持延迟加载的原理都是一样的
    6、简单的说一下MyBatis的一级缓存和二级缓存?
    Mybatis首先去缓存中查询结果集,如果没有则查询数据库,如果有则从缓存取出返回结果集就不走数据库。Mybatis内部存储缓存使用一个HashMap,key为hashCode+sqlId+Sql语句。value为从查询出来映射生成的java对象
    Mybatis的二级缓存即查询缓存,它的作用域是一个mapper的namespace,即在同一个namespace中查询sql可以从缓存中获取数据。二级缓存是可以跨SqlSession的。
    7、关于Hibernate和MyBatis的理解。
    Hibernate和MyBatis都是实现了ORM思想的框架。ORM就是对象关联关系映射,主要的目的就是想通过操作对象的方式来操作数据库。其中Hibernate是全自动的ORM框架实现,对JDBC进行高度封装,省去了大量的sql编写和基本的操作语句,提高了开发效率。但是执行效率,相比于jdbc、myBatis要低一些。而MyBatis是半自动的ORM框架,它需要我们手动去编写sql语句,只对返回的结果集进行了处理。这样既保证了执行的效率,又能省去了一部分的编码复杂程度。开发效率相比于hibernate要低一些,效率要高一些。如果是单纯的执行效率来说,JDBC的效率应该是最高的,当然开发效率却是最低的。如果使用hibernate,它也可以通过其他一些手段来提高效率,比如缓存,批量操作等等。如果是使用MyBatis,它可以支持mapping的映射,直接写一个mapper的接口,交给spring来管理,只要接口的方法名和sql的id一致,就可以轻松的调用方法。而且使用MyBatis的时候,可以通过map结构来发挥更简洁的结果集处理。通常会将持久层交给spring来管理,需要去继承相关的类,经常使用到的方法,比如hibernate里边有:saveOrUpdate、get、load、delete等。myBatis中有selectList,selectOne等等。Hibernate有一个延迟加载,这种方法查询数据时,只返回代理对象,并没有直接去访问数据库查询数据。当程序访问对象的属性的时候,才会去发起数据库查询。这样其实也是提高了查询效率,但是也存在一个session关闭的问题。解决的方法也很简单,在web.xml中配置OpenSessionInView这个Filte就可以解决这个问题。在处理对象关系的方面,hibernate提供了one2one,one2many,many2one,many2many这样的关系映射,需要在hbm.xml中进行配置(举个简单的例子:权限控制)。对于MyBatis框架而言,多表操作关键在于SQL。(此处接SQL优化的方案)。
    注意:可能被问到的问题
    1、ORM的具体理解。(核心技术:反射)
    a)反射是Java提供的一种访问机制。通过反射可以动态的访问类的内部信息,包括类的名称、属性、方法,设置是继承的父类信息。同时还可以动态调用方法(通过invoke方法调用)。
    2、Hibernate的描述(核心的API)
    3、Hibernate的缓存机制(三级缓存)
    4、Hibernate的一对一、一对多等关系的映射配置
    5、SQL语句
    8、数据库连接池
    1.1 原理
    连接池基本的思想是在系统初始化的时候,将数据库连接作为对象存储在内存中,当用户需要访问数据库时,并非建立一个新的连接,而是从连接池中取出一个已建立的空闲连接对象。使用完毕后,用户也并非将连接关闭,而是将连接放回连接池中,以供下一个请求访问使用。而连接的建立、断开都由连接池自身来管理。同时,还可以通过设置连接池的参数来控制连接池中的初始连接数、连接的上下限数以及每个连接的最大使用次数、最大空闲时间等等,也可以通过其自身的管理机制来监视数据库连接的数量、使用情况等。
    1.2 常见数据库连接池及其特点
    在Java中开源的常用的数据库连接池有以下几种 :
    1)DBCP
    DBCP是一个依赖Jakarta commons-pool对象池机制的数据库连接池.DBCP可以直接的在应用程序中使用,Tomcat的数据源使用的就是DBCP。
    2)c3p0
    c3p0是一个开放源代码的JDBC连接池,它在lib目录中与Hibernate一起发布,包括了实现jdbc3和jdbc2扩展规范说明的Connection 和Statement 池的DataSources 对象。
    3)Druid
    阿里出品,淘宝和支付宝专用数据库连接池,但它不仅仅是一个数据库连接池,它还包含一个ProxyDriver,一系列内置的JDBC组件库,一个SQL Parser。支持所有JDBC兼容的数据库,包括Oracle、MySql、Derby、Postgresql、SQL Server、H2等等。
    Druid针对Oracle和MySql做了特别优化,比如Oracle的PS Cache内存占用优化,MySql的ping检测优化。
    Druid提供了MySql、Oracle、Postgresql、SQL-92的SQL的完整支持,这是一个手写的高性能SQL Parser,支持Visitor模式,使得分析SQL的抽象语法树很方便。
    简单SQL语句用时10微秒以内,复杂SQL用时30微秒。
    通过Druid提供的SQL Parser可以在JDBC层拦截SQL做相应处理,比如说分库分表、审计等。Druid防御SQL注入攻击的WallFilter就是通过Druid的SQL Parser分析语义实现的。

11、
四、SSM
1、运行流程:
①.jsp(view)发送请求
②通过核心控制器DispatcherServlet调用请求解析器:HandlendMapping对请求进行解析,通过映射关系匹配到Controller层
③.在控制层调用业务逻辑层(service),数据持久层(DAO)返回控制层,请求完成获取一个结果,设置一个要跳转的视图,(ModelAndView装载并传输数据,设置视图)
④.核心控制器调用 视图解析器:ViewResolver解析视图,匹配相应的页面实现页面跳转
2、Ssm(springmvc+spring+ mybatis)的搭建步骤?
1).在项目中通过在web.xml配置springMVC的核心控制器DispatcherServlet并加载Spring-mvc-controller.xml,并且通过配置Spring的监听器contextLoaderListener加载spring-common.xml,
之后新建控制层并在类上加入@Controller和@RequestMapping注解,并通过@Resouce注入service层,
2).在service的实现类上加入@Service注解并通过@Autowired注入dao层,
dao层只有接口并没有实现类,是通过在mybatis中对应的含有sql语句的xml文件中来通过namespace指明要实现的dao层的接口,并使sql语句的id和dao层接口中的方法名一致从而明确调用指定dao层接口时要执行的sql语句。
3).并且在spring-mvc-controller.xml中配置了component-scan对controller进行扫描从而使控制层的注解生效还配置了内部视图解析器从而在控制层进行页面跳转时加上指定的前缀和后缀,
4).在spring-common.xml中配置了dbcp数据库连接池以及sqlSession来加载mapper下所有的xml并对所有的mapper层进行扫描也就是对dao层的扫描,还通过Aop中的切点表达式对service层进行事务控制,并且对service层进行扫描使其注解生效。
3. Junit单元测试:
我在编写完自己的功能模块后,为了保证代码的准确性,一般都会使用junit进行单元测试,
当时使用的是junit4这种基于注解的方式来进行单元测试。为了和spring集成获取配置的bean,
通常使用 @RunWith来加载junit这个核心类,使用 @ContextConfiguration来加载
相关的配置的文件,通过 @Resource按名字来注入具体的bean,最后在需要测试的方法上面加上
@Test 来进行单元测试。并且在编写单元测试的时候还要遵守一定的原则如:
源代码和测试代码需要分开;测试类和目标源代码的类应该位于同一个包下面,即它们的包名应该一样;
测试的类名之前或之后加上@Test,测试的方法名通常也以test开头。
@RunWith(SpringJUnit4ClassRunner.class)//运行spring相关环境 相当于spring监听功能
@ContextConfiguration(locations={“classpath:spring-common.xml”,“classpath:spring-datasource.xml”})//读取spring配置文件 不识别* 只能识别具体文件 多个配置文件使用string数据传递
public class TestSpring {
//注入Service层
private @Resource UserService userService;
@Test
public void testFind(){
List userList = userService.findAllUserInfo();
for (User user : userList) {
System.err.println(user.toString());
}
}
}

五、linux 篇
1、linux 常用的有几个版本(了解)
目前主流和常用的Linux版本主要有:
1、Redhat 版本5.5和6.0最新;培训、学习、应用、知名度最高的Linux发行版本,对硬件兼容性来说也比较不错,版本更新很快,对新硬件和新技术支持较好。
2、Debian 版本5.0和6.0最新;社区版的Linux来说是较好的,文档和资料较多,尤其是英文的。但在国内的占有率有一定的局限性。关键是上手难,但在所有的Linux发行版本中,这个版本应该说是最自由的。
3、SuSe 版本11和11.4最新;最华丽的Linux发行版,很多人都这样说,X windows和程序应用方面做的确实不错。尤其与Microsoft的合作关系,应该是在所有的Linux发行版本中最亲密的。
4、Ubuntu 版本9和10最新;最近几年出来的,主要指Server版本,强项就是其desktop版,应用是在太广泛了。
5、Centos 版本5.4和6.0最新;这个发行版主要是Redhat企业版的社区版,基本上跟redhat是兼容的,相对来说局限性教少。很多人都喜欢使用。
至少gentoo、mandriva、Slackware、redflag等可以暂时不考虑。虽然各自均有特点,但市场占有率和应用相对较少。
2、你对linux中的常用命令都了解那些
命令:

  1. ifconfig:查看IP地址
  2. java -version:查看jdk的版本
  3. rpm -qa | grep 软件的名称:查找和指定名称相关的软件
  4. rpm -ivh 软件名称:安装指定的软件
  5. rpm -e --nodeps 软件名称:卸载指定的软件
  6. uname -a:查看linux系统的基本信息(计算机名,操作的位数,版本号)
  7. ll(L):用来查看当前目录下的所有文件夹
  8. mkdirs 目录名:创建文件夹
  9. vi 文件名:对指定的文件名进行编辑 wq!:保存并退出 。q!:不保存并退出
  10. pwd:查看当前目录的完整路径
  11. unzip 文件名.zip:解压后缀名为zip的压缩文件
  12. mv 源文件名 目标件名:重命名的作用
  13. rm -rf 文件夹名:递归强制删除文件夹及其下面的所有子文件夹
  14. service iptables stop:禁用防火墙,service iptables status查看防火墙状态(centos6.5版本)
  15. chmod +x*.sh:使所有后缀名为sh的文件,拥有可执行权限
  16. 在bin目录下 ./startup.sh启动tomcat
  17. 在bin目录下通过tail -f …/logs/catalina.out来查看启动日志
  18. ps -f | grep 进程名:查看指定进程是否启动
  19. kill -9 进程号 :强制杀死进程
    3、你在linux系统上怎么部署项目的
    1.Linux上安装jdk,配置环境变量
    2.通过SSH将tomcat压缩包上传到Linux服务器,通过unzip解压缩
    3.开启防火墙中的8080端口号
    4.通过修改conf/server.xml部署项目
    5.通过chmod +x *.sh开启执行权限
    6.通过./startup.sh启动tomcat访问项目,
    并通过tail -f catalina.out来查看启动日志。

第五个月 概念总结
一、基础篇
1.你对xml和json是怎么理解的?
xml(可扩展标记语言)的特点:

  1. 有且只有一个根节点
  2. 它是数据传输的载体
  3. 它的所有标签都需要自定义,标签是成对出现的
  4. 它是纯文本文件
    xml里几个关键的术语 :
  5. 根节点(rootElement)
  6. 元素(Element)(开始节点,结束节点/开始元素,结束元素)有<>号的就是元素
  7. 属性(Attribute)(属性名,属性值)在开始节点中的东西就是属性
  8. 文本(text)
    例子:
    <students(根节点也叫根元素)>
    <student id=“1”(id属性名,1是属性值)>
    小花(文本)
    20(文本)
    </student(子节点也叫根节点)>

    json(全称:JavaScriptObjectNotation(javascript对象表式))
    json对象分为两种格式:
    json对象(就是在{}中存储键值对,健和值之间用冒号分割,键值对之间用逗号分割)
    json数组:(就是在[]中存储多个json对象,json对象之间用逗号分割(两者之间可以进行相互嵌套)数据传输的载体之一)

2.final,finally,finalize 三者区别
Final是一个修饰符:
当final修饰一个变量的时候,变量变成一个常量,它不能被二次赋值,当final修饰的变量为静态变量(即由static修饰)时,必须在声明这个变 量的时候给它赋值。当final修饰方法时,该方法不能被重写,当final修饰类时,该类不能被继承Final不能修饰抽象类,因为抽象类中会有需要子类实现的抽象方法,(抽 象类中可以有抽象方法,也可以有普通方法,当一个抽象类中没有抽象方法时,这个抽象类也就没有了它存在的必要)Final不能修饰接口,因为接口中有需要其实现类来实现的方法
Finally:
Finally只能与try/catch语句结合使用,finally语句块中的语句一定会执行, 并且会在return,continue,break关键字之前执行
finalize:
Finalize是一个方法,属于java.lang.Object类,finalize()方法是GC (garbage collector垃圾回收)运行机制的一部分,finalize()方法是在 GC清理它所从 属的对象时被调用的
3、什么叫GC?
GC的全称是garbage collection,中文名称垃圾回收,是.java中对内存管理的一种功能。垃圾回收器跟踪并回收托管内存中分配的对象,定期执行垃圾回收 以回收分配给没有 有效引用的对象的内存。当使用可用内存不能满足内存请求时,GC会自动进行。

在进行垃圾回收时,垃圾回收器首先搜索内存中的托管对象,然后从托管代码中搜索被引用的对象并标记为有效,接着释放没有被标记为有效的对象并收回内存,最后整理内存将有效对象挪动到一起。这就是GC的四个步骤。

由上可见,GC是很影响性能的,所以一般说来这种事情况还是尽量少发生为好。

为了减少一些性能影响,.net的GC支持对象老化,或者说分代的概念,代是对象在内存中相对存现时期的度量单位,对象的代数或存现时期说明对象所属的代。目前.net的垃圾回收器支持三代。每进行一次GC,没有被回收的对象就自动提升一代。较近创建的对象属于较新的代,比在应用程序生命周期中较早创建的对象的代数低。最近代中的对象位于零代中。每一次GC的时候,都首先回收零代中的对象,只有在较低代数的对象回收完成后仍不能满足需求的情况下才回收较高代数的对象。

二、数据库篇
1、索引的概述
1、索引的概念
索引就是为了提高数据的检索速度。
数据库的索引类似于书籍的索引。
在书籍中,索引允许用户不必翻阅完整个书就能迅速地找到所需要的信息。
在数据库中,索引也允许数据库程序迅速地找到表中的数据,而不必扫描整个数据库.
2、索引的优点
1.创建唯一性索引,保证数据库表中每一行数据的唯一性
2.大大加快数据的检索速度,这也是创建索引的最主要的原因
3.减少磁盘IO(向字典一样可以直接定位)
3、索引的缺点
1.创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加
2.索引需要占用额外的物理空间
3.当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,降低了数据的维护速度
4、索引的分类
1.普通索引和唯一性索引
普通索引:CREATE INDEX mycolumn_index ON mytable (myclumn)
唯一性索引:保证在索引列中的全部数据是唯一的
CREATE unique INDEX mycolumn_index ON mytable (myclumn) 
2. 单个索引和复合索引
单个索引:对单个字段建立索引
复合索引:又叫组合索引,在索引建立语句中同时包含多个字段名, 最多16个字段
CREATE INDEX name_index ON userInfo(firstname,lastname)
3.顺序索引,散列索引,位图索引
2、oracle三层分页
select * from (select t.*, rownum rn from (select * from menu order by id desc) t where rownum < 10) where rn >=5
3、数据库的三大范式和五大约束?
数据库设计三大范式(重点):
第一范式(1NF):数据表中的每一列(每个字段)必须是不可拆分的最小单元,也就是确保每一列的原子性;
例如:userInfo:山东省烟台市 131777368781 userAds:山东0省烟台市 userTel:131777368781

第二范式(2NF):满足1NF后,要求表中的所有列,都必须依赖于主键,而不能有任何一列与主键没有关系,也就是说一个表只描述一件事情;
例如:订单表只描述订单相关的信息,所以所有字段都必须与订单id相关 产品表只描述产品相关的信息,所以所有字段都必须与产品id相 关;因此不能在一张表中同时出现订单信息与产品信息;如下图所示:

第三范式(3NF):必须先满足第二范式(2NF),要求:表中的每一列只与主键直接相关而不是间接相关,(表中的每一列只能依赖于主键);
例如:订单表中需要有客户相关信息,在分离出客户表之后,订单表中只需要有一个用户id即可,而不能有其他的客户信息。因为其他的客户信息直接关联于用户id,而不是直接与订单id直接相关。

【如何更好的区分三大范式】
第 一范式和第二范式在于有没有分出两张表,第二范式是说一张表中包含了所种不同的实体属性,那么要必须分成多张表, 第三范式是要求已经分成了多张表,那么一张表中只能有另一张表中的id(主键),而不能有其他的任何信息(其他的信息一律用主键在另一表查询)。
【数据库五大约束】
1.primary KEY:设置主键约束;
2.UNIQUE:设置唯一性约束,不能有重复值;
3.DEFAULT 默认值约束,height DOUBLE(3,2)DEFAULT 1.2 height不输入是默认为1,2
4.NOT NULL:设置非空约束,该字段不能为空;
5.FOREIGN key :设置外键约束。
4、就业必会 复杂sql?
1):oracle 分页:
select * from (select t.*, rownum rn from (select * from menu order by id desc) t where rownum < 10) where rn >=5
2): mysql 分页:
select * from music where id limit 5,5
3):oracle中如何快速将一张表的数据复制到另外一张表中(另外一张表不存在,另外一张表存在,但数据为空)。
不存在另一张表时:(表的备份)
create table 新表 as select * from 将要复制的表
存在另一张表时:(批量插入)
insert into 新表名 select 字段 from 将要复制的表名
4)音乐专辑查询出special app:ds:special表中的id 专辑名 并下面有多少首歌曲:
Select s.id , min(s.sname),count(m.mid) from special s inner join ms m on s.id=m.id group by s.id
5):快速删除一张表(不可事物回滚,也就是没有日志记录)
TRUNCATE from 表名
6):inner join:
select 查找信息 from 表名 1 inner join 表名2 on 表名1.列名 = 表名2.列名
7):left join:
左外连接 select 查找信息 from 表名1 left join 表名2 on 表名1.列名 = 表名2.列名
8):right join:
右外连接 select 查找信息 from 表名1 right join 表名2 on 表名1.列名 = 表名2.列名

9):oracle中查询遍历树形结构(start with)
select * from extmenu start with pid=1 connect by prior id = pid
快速删除父节点以及父节点下的所有节点:
Delete from extmenu where id in (elect * from extmenu start with pid=1 connect by prior id = pid)
10):查询出来60-70,80-90,95-100学生的信息:
select * from stu where chengji between 60 and 70 or between 80 and 90 or between 95 and 100
select * from stu where chengji > 60 and chengji < 70 or chengji > 80 and chengji < 90 or chengji > 95 and chengji < 100
11):用exists替换in------进行联表查询:
select * from dept where exists(select * from emp where emp.deptno=dept.deptno);
或 select * from dept d inner join emp e on d.deptno = e.deptno(只查询出两表共同拥有的字段数据)
12):删除表中的重复数据:
delete from xin a where a.rowid != (select max(b.rowid) from xin b where a.name = b.name);
13):row_number(),rank() over ,dense_rank() over 按工资排序:
select sal, row_number() over(order by sal desc) rank1,rank() over(order by sal desc) rank,dense_rank() over(order by sal desc) drank from emp
14):select * from (select emp.* from( dense_rank() over(partition by departNo order by sal desc) rk from emp ) Where rk=4

三、框架篇
1、你对maven是怎么理解的?
接触到正式工作不久接触到了maven,我花费了一些时间研究了
maven,知道maven是一个项目管理工具,其核心特点就是通过maven可以进行jar包的依赖管理,保证jar包版本的一致性,以及可以使多个项目共享jar包,从而能够在开发大型java应用的时候,减小项目的大小,maven根据“约定优于配置”的特性,可以对其项目的编译打包部署进行了更为抽象的封装,我 们可以直接使用系统预定好的mvn clean,package等命令进行项目的操作。于是我就在网上购物商城系统中采用了maven,为了保证团队中的成员能够节省下载jar包所需要的时间,于是我就搭建了在局域网内的maven私服,然后通过配置settings.xml中建立mirror镜像,将所有下载jar包的请求都转发到maven私服上,之后通过在pom.xml即(project object model)中配置项目所依赖的jar包,从而达到在构建项目的时候,先从本地仓库中查找,如果不存在从内部私服查找,如果不存在最后再从外网服务器查找的机制,达到了节省下载带宽,提高开发效率,以及jar包重用的目的。
2、Mybatis介绍之缓存
Mybatis中有一级缓存和二级缓存,默认情况下一级缓存是开启的,而且是不能关闭的。一级缓存是指SqlSession级别的缓存,当在同一个SqlSession中进行相同的SQL语句查询时,第二次以后的查询不会从数据库查询,而是直接从缓存中获取,一级缓存最多缓存1024条SQL。二级缓存是指可以跨SqlSession的缓存。
Mybatis中进行SQL查询是通过org.apache.ibatis.executor.Executor接口进行的,总体来讲,它一共有两类实现,一类是BaseExecutor,一类是CachingExecutor。前者是非启用二级缓存时使用的,而后者是采用的装饰器模式,在启用了二级缓存时使用,当二级缓存没有命中时,底层还是通过BaseExecutor来实现的。
注意:参考文档:https://blog.csdn.net/educast/article/details/55209660
3、Mybatis的批量操作数据库?(了解,并会使用)
1).批量插入insert:


SELECT LAST_INSERT_ID()

INSERT INTO sourcedoc (
sdate, sweek,
roomno, daysched, nightsched,
adminsched, vacationsched, programdept,
programname
)values

(
#{item.sdate},#{item.sweek},#{item.roomno},
#{item.daysched},#{item.nightsched},#{item.adminsched},
#{item.vacationsched},#{item.programdept},#{item.programname}
)


2).批量删除(delete) :

DELETE FROM LD_USER WHERE ID in #{item} 3).批量修改(update) : update orders set state = '0' where no in #{nos} 4、easyui分页的实现思路? 1).导入jquery和easyui的js文件,第二,在body中声明一个table当载体也就是dategrid在页面上的位置,然后通过js方法初始化datagrid 首先,定义colomn这个来规定当前表格有几列,标题和字段名称。 2).第二还有url 这个是后台返回json的数据 ,还有需要加入 pagination =true开启分页组件,同时 后台定义page rows 来接收前台传过来的 当前页 和每页几条,然后用持久层技术,求出 对应的数据,还有总条数。 3).需要注意的是,返回的 list数据 必须叫rows 总条数必须叫total。

5、easyui常用组件?
Tree(树)、panel(面板)、Accordion(手风琴)、Tabs(选项卡)、Layout(布局)、DataGrid(数据表格)、ProgressBar(进度条)、Form(表单)、SearchBox(搜索框)、textbox(文本框)、FileBox(文件框)、comboBox(组合框)、NumberBox(号码框)、Messager(消息)
6、easyui常用组件属性及方法?
Easyui tab判断选项卡是否已经存在exists
Easyui 自动适应屏幕 fit:true
Easyui datagrid 只能选择一行singleSelect:true
Easyui tree 绑定点击事件 onClick:function(node){}
Easyui datagrid 绑定点击事件 单击:onClickRow 双击:onDblClickRow
Easyui tabs 动态添加选项卡$(’#myTabs’).tabs(‘add’,{title: 标题,content:内容, closable:true//是否可关闭})
Easyui dialog 动态打开弹框 $(‘#myDialog’).dialog(‘open’)
Easyui 打开消息框 $.messager.alert(‘提示’,‘请选择需要修改的数据’,‘warning’);
Easyui 表单重置、提交 $(’#addForm’).form(‘reset’); KaTeX parse error: Expected 'EOF', got '#' at position 3: ('#̲addForm').form(….messager.show({title:‘你的消息’}),成功,首先我通过给body添加一个easyui-layout的样式并结合region:‘north’;region:‘west’;region:'center’将整个窗口分为上左中,然后在左边用easyui-tree来进行菜单的展示,之后在中间区域通过easyui tabs来加入选项卡,而在选项卡中就是一个个的datagrid数据列表,分页以及form,其中我在做easyui tabs选项卡这一模块的时候,在做的过程中就遇到了二个问题,一个就是在加载页面的时候先创建了一个tab页面,让它展示在中间位置,然后点击左边Tree菜单调用tabs的add方法动态添加一个个的tab选项卡,但是做的过程中出现了相同的选项卡会重复添加的这么一个问题,然后我去查了一些相关资料,最后通过tab的唯一标识判断tab是否存在,如果存在则调用tabs的select方法来激活该选项卡,让它选中,否则就添加一个tab。最后达到了tab不存在就添加,存在就选中的效果。这样这个问题就解决了,第二个就是在用tab加载界面的时候,界面里面的js不会执行。后来查询了很多资料才知道是什么原因,原来不管是window,dailog还是tab其实质最终都是继承了panel。panel有两种方式展示内容。第一是直接硬编码写出来。第二是通 过href属性,加载外部html片段,这个在easyui里是一个很重要的概念,原来之前加载的是整个html页面!知道了这个原因最终把问题解决了!
8、bootstrap常用组件?
bootstrap-treeview(树)、bootStrap-addTabs(选项卡)、bootstrap-table(表格)、bootstrap-datetimepicker(时间)、bootstrap-bootbox(弹框)、bootstrap-fileinput(上传)
9、bootstrap常用css样式?
布局容器
.container 类用于固定宽度并支持响应式布局的容器。
.container-fluid 类用于 100% 宽度,占据全部视口(viewport)的容器。
表格
.table
.table-striped 类可以给 之内的每一行增加斑马条纹样式。
.table-bordered 类为表格和其中的每个单元格增加边框。
.table-hover 类可以让 中的每一行对鼠标悬停状态作出响应。
.table-condensed 类可以让表格更加紧凑,单元格中的内补(padding)均会减半。
将任何 .table 元素包裹在 .table-responsive 元素内,即可创建响应式表格,其会在小屏幕设备上(小于768px)水平滚动。当屏幕大于 768px 宽度时,水平滚动条消失。
状态类
Class 描述
.active 鼠标悬停在行或单元格上时所设置的颜色
.success 标识成功或积极的动作
.info 标识普通的提示信息或动作
.warning 标识警告或需要用户注意
.danger 标识危险或潜在的带来负面影响的动作
表单
.form-group 表单组
.form-inline 内联表单
.form-inline 类可使其内容左对齐并且表现为 inline-block 级别的控件。只适用于视口(viewport)至少在 768px 宽度时(视口宽度再小的话就会使表单折叠)。
水平排列表单
.form-horizontal 类,并联合使用 Bootstrap 预置的栅格类,可以将 label 标签和控件组水平并排布局。这样做将改变 .form-group 的行为,使其表现为栅格系统中的行(row),因此就无需再额外添加 .row 了。
.btn 按钮
.btn-default 默认样式
.btn-primary 主题样式(深蓝)
.btn-success 成功样式(绿)
.btn-info 一般信息样式(淡蓝)
.btn-warning 警告样式(黄)
.btn-danger 危险样式(红)
.btn-lg 大按钮
.btn-sm 小按钮
.btn-xs 超小按钮
.img-rounded 图片样式方形圆角
.img-circle 图片样式圆形
.img-thumbnail 图片样式方形圆角边框
栅格系统
超小屏幕 手机 (<768px) 小屏幕 平板 (≥768px) 中等屏幕 桌面显示器 (≥992px) 大屏幕 大桌面显示器 (≥1200px)
栅格系统行为 总是水平排列 开始是堆叠在一起的,当大于这些阈值时将变为水平排列C
.container 最大宽度 None (自动) 750px 970px 1170px
类前缀 .col-xs- .col-sm- .col-md- .col-lg-
列(column)数 12
最大列(column)宽 自动 ~62px ~81px ~97px
槽(gutter)宽 30px (每列左右均有 15px)
可嵌套 是
偏移(Offsets) 是
列排序 是
10、session和cookie的区别?
session是存储在服务器端,cookie是存储在客户端的,所以安全来讲session的安全性要比cookie高,然后我们获取session里的信息是通过存放在会话cookie里的sessionid获取的。又由于session是存放在服务器的内存中,所以session里的东西不断增加会造成服务器的负担,所以会把很重要的信息存储在session中,而把一些次要东西存储在客户端的cookie里,然后cookie确切的说分为两大类分为会话cookie和持久化cookie,会话cookie确切的说是存放在客户端浏览器的内存中,所以说他的生命周期和浏览器是一致的,浏览器关了会话cookie也就消失了,然而持久化cookie是存放在客户端硬盘中,而持久化cookie的生命周期就是我们在设置cookie时候设置的那个保存时间,然后我们考虑一问题当浏览器关闭时session会不会丢失,从上面叙述分析session的信息是通过sessionid获取的,而sessionid是存放在会话cookie当中的,当浏览器关闭的时候会话cookie消失所以我们的sessionid也就消失了,但是session的信息还存在服务器端,这时我们只是查不到所谓的session但它并不是不存在。那么,session在什么情况下丢失,就是在 服务器关闭的时候,或者是sessio过期,再或者调用了invalidate()的或者是我们想要session中的某一条数据消失调用session.removeAttribute()方法,然后session在什么时候被创建呢,确切的说是通过调用session.getsession来创建,这就是session与cookie的区别
11、如果项目中有异常该怎么处理?业务逻辑层能不能捕获异常?(了解)
首先需要明确一个理念:异常是抛给程序员的,而不是抛给用户的。
明确了这个理念之后就好理解了,为什么需要在表现层处理异常——因为表现层是程序员和用户之间的最后一道屏障,必须把异常包装得漂漂亮亮的丢给客户,也就是所谓的用户体验。
然而,表现层绝对不是唯一要处理异常的地方,你所说的那些地方,包括底层、服务器……都需要适当的处理异常。
比如说,服务端提供的接口,一般要考虑调用者的体验,所以不会直接抛异常出来,而是需要进行一定的封装,同时在服务端记录异常信息以便查错。
当然为了简化和统一处理过程,通常会集中在某些层次,包括表现层对异常进行处理。
应该在service曾定义好异常情况,遇到问题时抛出异常(RuntimeException),然后再表现层根据异常种类做出相应的动作。这样就是view层依赖于serivce层,而service层可以为更多种view层提供服务了。但是这样也有一些问题,就是如果serivce逻辑复杂,可能异常种类就非常多,这样项目做起来也很麻烦。
异常不要用来做流程控制,条件控制,因为异常的处理效率比条件分支低。
对大段代码进行 try-catch,这是不负责任的表现。 catch 时请分清稳定代码和非稳定代码,稳定代码指的是无论如何不会出错的代码。对于非稳定代码的 catch 尽可能进行区分异常类型,再做对应的异常处理。
捕获异常是为了处理它,不要捕获了却什么都不处理而抛弃之,如果不想处理它,请将该异常抛给它的调用者。最外层的业务使用者,必须处理异常,将其转化为用户可以理解的内容。
有 try 块放到了事务代码中, catch 异常后,如果需要回滚事务,一定要注意手动回滚事务。
finally 块必须对资源对象、流对象进行关闭,有异常也要做 try-catch。说明: 如果 JDK7,可以使用 try-with-resources 方式。
不能在 finally 块中使用 return, finally 块中的 return 返回后方法结束执行,不会再执行 try 块中的 return 语句。
捕获异常与抛异常,必须是完全匹配,或者捕获异常是抛异常的父类。说明: 如果预期对方抛的是绣球,实际接到的是铅球,就会产生意外情况。
、方法的返回值可以为 null,不强制返回空集合,或者空对象等,必须添加注释充分说明什么情况下会返回 null 值。调用方需要进行 null 判断防止 NPE 问题。
说明: 本规约明确防止 NPE 是调用者的责任。即使被调用方法返回空集合或者空对象,对调用者来说,也并非高枕无忧,必须考虑到远程调用失败,运行时异常等场景返回 null 的情况。
、在代码中使用“抛异常”还是“返回错误码”,对于公司外的 http/api 开放接口必须使用“错误码”; 而应用内部推荐异常抛出; 跨应用间 RPC 调用优先考虑使用 Result 方式,封装 isSuccess、 “错误码”、 “错误简短信息”。
、定义时区分 unchecked / checked 异常,避免直接使用 RuntimeException 抛出,更不允许抛出 Exception 或者 Throwable,应使用有业务含义的自定义异常。推荐业界已定义过的自定义异常,如: DAOException / ServiceException 等。
、对于运行时异常,我们不要用try…catch来捕获处理,而是在程序开发调试阶段,尽量去避免这种异常,一旦发现该异常,正确的做法就会改进程序设计的代码和实现方式,修改程序中的错误,从而避免这种异常。捕获并处理运行时异常是好的解决办法,因为可以通过改进代码实现来避免该种异常的发生。对于受检查异常,没说的,老老实实去按照异常处理的方法去处理,要么用try…catch捕获并解决,要么用throws抛出!对于Error(运行时错误),不需要在程序中做任何处理,出现问题后,应该在程序在外的地方找问题,然后解决。
四、技术篇
1、redis的三大特点以及优势,redis常用数据类型(标记理解,认识,必须掌握)?
Redis简介
Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。
Redis 与其他 key - value 缓存产品有以下三个特点:
Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
Redis支持数据的备份,即master-slave模式的数据备份。
Redis 优势
性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
原子 – Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。
丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。
Redis 数据类型
Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。

2、什么是缓存穿透,什么是缓存雪崩,以及如何解决?
缓存穿透
什么是缓存穿透?
一般的缓存系统,都是按照key去缓存查询,如果不存在对应的value,就应该去后端系统查找(比如DB)。如果key对应的value是一定不存在的,并且对该key并发请求量很大,就会对后端系统造成很大的压力。这就叫做缓存穿透。

如何避免?
1:对查询结果为空的情况也进行缓存,缓存时间设置短一点,或者该key对应的数据insert了之后清理缓存。
2:对一定不存在的key进行过滤。可以把所有的可能存在的key放到一个大的Bitmap中,查询时通过该bitmap过滤。【感觉应该用的不多吧】
缓存雪崩
什么是缓存雪崩?
当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(比如DB)带来很大压力。
如何避免?
1:在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
2:不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。
3:做二级缓存,A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期(此点为补充)

3、redis与memcache的区别分析
1、 Redis和Memcache都是将数据存放在内存中,都是内存数据库。不过memcache还可用于缓存其他东西,例如图片、视频等等。
2、Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,hash等数据结构的存储。
3、虚拟内存–Redis当物理内存用完时,可以将一些很久没用到的value 交换到磁盘
4、过期策略–memcache在set时就指定,例如set key1 0 0 8,即永不过期。Redis可以通过例如expire 设定,例如expire name 10
5、分布式–设定memcache集群,利用magent做一主多从;redis可以做一主多从。都可以一主一从
6、存储数据安全–memcache挂掉后,数据没了;redis可以定期保存到磁盘(持久化)
7、灾难恢复–memcache挂掉后,数据不可恢复; redis数据丢失后可以通过aof恢复
8、Redis支持数据的备份,即master-slave模式的数据备份。
4、Redis 和 spring整合的步骤。Redis的使用业务场景。哪些东西不适合用缓存?
1.在什么情况下使用以及两条以上: 我们简单举个实例来描述下hash的应用场景,比如我们要存储一个用户信息对象数据,包含以下信息:
用户id为查找的key,存储的value用户对象包含姓名,年龄,生日等信息,如果用普通的key/value结构来存储,主要有以下2种存储方式:

第一种方式将用户id作为查找key,把其他信息封装成一个对象以序列化的方式存储,这种方式的缺点是,增加了序列化/反序列化的开销,并且在需要修改其中一项信息时,需要把整	个对象取回,并且修改操作需要对并发进行保护,引入cas等复杂问题。
第二种方法是这个用户信息对象有多少成员就存成多少个key-value对儿,用用户id+对应属性的名称作为唯一标识来取得对应属性的值,虽然省去了序列化开销和并发问题,但是用	户id为重复存储,如果存在大量这样的数据,内存浪费还是非常可观的。

Redis 和 spring整合的步骤:
2. 1.首先,我们需要引入基本的jar包。

org.springframework.data
spring-data-redis
1.4.2.RELEASE


redis.clients
jedis
2.6.2

2.然后,在applicationContext中配置
3.开启事务,可以通过transcational注解控制
4.我们需要为其配置redis服务器的账户密码,端口号
5.完成之后我们在进行test测试,看看是否成功。
redis在项目中遇到的问题:
1).缓存穿透的问题:
一般出现这样的问题,是因为当我们查询一条肯定不存在的数据的时候,缓存中没有,就会透过缓存来查询数据库,数据库也不存在,这样就会将值保存在缓存中 最后还是缓存和数据库中都没有,如果一直访问这条数据。我们就对数据库进行频繁的查询给数据库带来压力。

	解决办法:当查询的时候,如果缓存和数据库中都没有,我们就将这个数据以空的形式存放在缓存中,(或者是给一个false的标示)这样就不用去数据库就可以知			道不存在,减少对数据库查询的次数。当我们这个值发生改变的时候,我们在重新赋值。

	2.并发情况:
		当我们大量访问都是查询一个缓存中没有的数据时,这样就会去数据库中进行查询,可能会造成数据库岩机,
		解决办法:在查询的时候,我给它添加一个同步锁,只有第一条数据去,数据库中查询并返回到redis中后才能查询,这是数据库中已近存在了值,这样可以避免;
	3.雪崩:
		大量数据的访问缓存超时,这样用户就会访问到数据库,第一台数据库崩溃了,访问就会到第三台数据库进行查询,这样就会导致额第二台崩溃。
		解决办法:就是设置失效时间,不要一起失效,或者是设置在访问少的时候,或者设置永远不失效。

5、mongodb常用命令?(了解)
show dbs 》查询所有数据库
show collections:显示当前数据库中的集合(类似关系数据库中的表)
show users:显示用户
use dbname 》 选择某个库使用 没有库时自动创建
db.dropDatabase() 》删除当前使用的数据库
db.getName() 或 db 》查看数据库
db.stats() 》查看数据库状态
db.version() 》查看mongodb版本
db.student.find(); 》查询student表下的所有数据 相当于select* from student
db.student.find().pretty();》格式化输出的json
db.student.findOne(); 》查找表中第一条数据
db.student.find().limit(100);
db.student.find({ }).count(); 》统计当前表的数量 》相当于 select count(1) from student;
db.student.find({ }).skip(1).limit(50); 》跳过第一条查询后50条
db.userInfo.distinct(“name”); 》去除出name重复的数据 相当于select distict name from userInfo;
db.student.find({“age”:“6”}) 》带条件查询 查询年龄等于6岁的 相当于 select * from student where age = 6;
db.student.find({“age”:{KaTeX parse error: Expected 'EOF', got '}' at position 6: gt:10}̲}) 查询大于10岁的学生 {…gt:10}}
$gt 大于 $lt 小于 $gte 大于等于 $lte 小于等于 KaTeX parse error: Expected '}', got 'EOF' at end of input: …t.find({"age":{gt:10,KaTeX parse error: Expected 'EOF', got '}' at position 6: lt:30}̲}) 》年龄范围查询 查询大于…or:[{“age”:6},{“name”:“lsi”}]}); 》or 查询 相当于 select * from student where age =6 or name = ‘lsi’;
db.student.find({“name”:/s/}) 》模糊查询 查询名字中带有s的人 相当于 select * from student where name like ‘%s%’; // 相当于 %%
db.student.find({“name”:/^zhang/}) 》查看姓zhang的学生 相当于 select * from student where name like ‘zhang%’; ^标识一什么开头 相当于js正则中的用法
db.student.find({“name”:/san$/}) 》查询名字san结尾的学生 相当于 select * from student where name like ‘%san’; 相 当 于 j s 正 则 中 的 用 法 d b . s t u d e n t . f i n d ( ) . s o r t ( &quot; a g e &quot; : 1 ) ; 》 按 照 年 龄 正 着 排 序 相 当 于 s e l e c t ∗ f r o m s t u d e n t o r d e r b y a g e a s c ; d b . s t u d e n t . f i n d ( ) . s o r t ( &quot; a g e &quot; : − 1 ) ; 》 按 照 年 龄 倒 着 排 序 相 当 于 s e l e c t ∗ f r o m s t u d e n t o r d e r b y a g e d e s c ; d b . s t u d e n t . e n s u r e I n d e x ( &quot; n a m e &quot; : 1 ) ; 》 创 建 索 引 d b . s t u d e n t . t o t a l I n d e x S i z e ( ) ; 》 查 看 总 索 引 记 录 大 小 d b . s t u d e n t . g e t I n d e x e s ( ) ; 》 查 询 当 前 聚 集 集 合 所 有 索 引 修 改 d b . c o l l e c t i o n . u p d a t e ( c r i t e r i a , o b j N e w , u p s e r t , m u l t i ) c r i t e r i a : u p d a t e 的 查 询 条 件 , 类 似 s q l u p d a t e 查 询 内 w h e r e 后 面 的 o b j N e w : u p d a t e 的 对 象 和 一 些 更 新 的 操 作 符 ( 如 相当于 js正则中的用法 db.student.find().sort({&quot;age&quot;:1}); 》按照年龄正着排序 相当于 select * from student order by age asc; db.student.find().sort({&quot;age&quot;:-1}); 》按照年龄倒着排序 相当于 select * from student order by age desc; db.student.ensureIndex({&quot;name&quot;:1});》 创建索引 db.student.totalIndexSize(); 》查看总索引记录大小 db.student.getIndexes(); 》查询当前聚集集合所有索引 修改 db.collection.update(criteria, objNew, upsert, multi ) criteria:update的查询条件,类似sql update查询内where后面的 objNew:update的对象和一些更新的操作符(如 jsdb.student.find().sort("age":1);selectfromstudentorderbyageasc;db.student.find().sort("age":1);selectfromstudentorderbyagedesc;db.student.ensureIndex("name":1);db.student.totalIndexSize();db.student.getIndexes();db.collection.update(criteria,objNew,upsert,multi)criteria:updatesqlupdatewhereobjNew:update,KaTeX parse error: Expected '}', got 'EOF' at end of input: …ate({"age":6},{set:{“name”:“zhaoliu”}},false,true); 相当于 update student set name=‘zhaoliu’ where age = 6;
db.student.update({“age”:6},{KaTeX parse error: Expected 'EOF', got '}' at position 15: inc:{"age":10}}̲,false,true); 相…set:{score:0}},true,true)
删除列
db.student.update({},{$unset:{score:0}},true,true)
mongodb启动命令
./mongod --dbpath=数据存储地址 --logpath=日志存储地址

6、Redis 和Mongodb 的 区别?
1.Mogodb 是非关系数据,基于bson格式的数据库 ,有关键字可以进行分页,姓名模糊匹配,大于小于等,mogon是最向关系型数据库的非关系行数据库
2.Redis 是一个缓存的技术,mongo的数据都存在硬盘当中,而redis数据是存放在内存当中的,只是 它支持 持久化到硬盘的操作,所以可以理解为 非关系数据库,但需要注意的是,redis是通过键值对的存储方式,不支持模糊,条件查询

7、Mongodb 和spring整合 步骤。 spring 提供的工具类,常见方法。 mongdb 使用的业务场景。哪些业务使用Mongodb 反而会麻烦?
mongodb是非关系型数据库,他的存储数据可以超过上亿条(老版本的mongodb有丢数据的情况,新版本不会有,网上说的),mongodb适合存储 一些量大表关系较简单的数据
从目前阿里云 MongoDB 云数据库上的用户看,MongoDB 的应用已经渗透到各个领域,比如游戏、物流、电商、内容管理、社交、物联网、视频直播等,以下是几个实际的应用案例。
游戏场景,使用 MongoDB 存储游戏用户信息,用户的装备、积分等直接以内嵌文档的形式存储,方便查询、更新
物流场景,使用 MongoDB 存储订单信息,订单状态在运送过程中会不断更新,以 MongoDB 内嵌数组的形式来存储,一次查询就能将订单所有的变更读取出来。
社交场景,使用 MongoDB 存储存储用户信息,以及用户发表的朋友圈信息,通过地理位置索引实现附近的人、地点等功能
物联网场景,使用 MongoDB 存储所有接入的智能设备信息,以及设备汇报的日志信息,并对这些信息进行多维度的分析
视频直播,使用 MongoDB 存储用户信息、礼物信息等
Spring和mongodb整合步骤:
添加依赖的jar包
定义实体类
Spring配置
新建application.xml配置文件
然后编写操作mongodb的接口
再写对应接口的实现类:
测试类开始进行测试

8、简单介绍一下你对Webservice的理解
我谈一谈我对webservice的理解
我在做电商项目的时候,支付成功的短信提醒的时候,我需要调用中国移动的这个发送短信的这个接口,我当时是通过webservice的方式,
webservice是SOA(面向服务编程)的一种实现,主要是用来实现异构平台通信也就是不同平台不同项目之间的数据传输,从而避免了信息孤岛的问题,它之所以能够进行异构平台通信是因为它是完全基于xml的,所以说,webService是跨平台,跨语言,跨框架的。常用的开发webservice的技术框架有xfire,cxf,axis2,其中cxf是xfire的升级版本,适用于java语言,并且和spring整合起来也比较方便,axis2虽然功能比较强大但性能相对较低,通过上面分析,结合我们目前的两个项目都是基于java语言的,所以我采用cxf这种方式实现了两个项目之间数据的传递,我们为了保证webservice的安全性我们采用了基于WS-Security标准的安全验证(使用CXF回调函数)。
下面我详细说一下使用cxf是如何开发webservice的
cxf有两种方式开发webservice,一种是使用cxf自带的服务器jetty开发,一种是与spring结合起来使用
使用jetty开发:
服务端:
需要导入cxf-rt-transports-http-jetty.jar包,写一个接口和实现类,在接口的类名上需加@WebService注解,接口的方法上需加@WebMethod注解,之后写一个发布类,使用EndPoint.publish()方法发布服务,访问发布的地址,查看生成的wsdl文档是否完整(完整的wsdl文档包含types messages portType binding service五部分);
客户端:
首先根据服务端发布的地址使用cxf框架工具或jdk(1.6版本以上)生成中间桥梁类,然后写一个中间桥梁类的服务类,通过调用中间桥梁类中的方法来访问服务端数据,从而达到了远程调用的目的
Spring与cxf结合
webservice服务端配置流程
首先在web.xml中引入cxfServlet核心类,指定对以/cxf开头的url路径提供webservice服务,之后我们在要发布成webservice接口上添加@Webservice 注解,而且还要在实现类上添加同样的webservice注解并且要说明实现了哪个接口,之后在spring-webservice.xml中发布webservice服务,通过jaxws:endpoint这个标签,并且在标签配置implementor和address来表明实现服务的类,以及发布的地址,最后在浏览器中输入相关的webservice地址?wsdl来验证服务是否发布成功。
webservice客户端的配置
首先通过wsdl2java根据发布的webservice服务端地址的wsdl生成客户端调用的中间桥梁java类,将生成的java类拷贝到客户端项目中,配置spring-client.xml文件,通过jaxws:client定义一个bean,并通过address属性指明要访问的webservice的服务地址,通过serviceClass指明充当中间桥梁的服务类,之后获取该bean,就可以通过它来访问发布的webservice接口中的方法。
9、HttpClient的讲解
httpClient是apache旗下的子项目适用于多项目之间的数据传输,httpClinet与webservice不同,webservice是一个重量级的框架,适用于跨域和跨项目之间的数据传输,而httpClient是一个轻量级的框架,使用起来相对比较灵活、易用,
httpClient使用步骤,
1、创建HttpClient实例;
2、创建连接方式实例,在这里有两种连接方式:GetMethod和PostMethod
3、执行httpClient对象的excute方法;
4、读取response方法;
5、处理返回的结果,
首先判断状态码为200的说明连接成功,然后在执行 HttpEntity entity=response.getEntity();;获得相应的实体;
使用super.outString(EntityUtils.toString(entity),responsed)
将数据传输到前台
6、关闭资源,释放连接;httpclient.close();
项目中的应用以及遇到的问题:
当时我们在做大眼睛房地产项目时候,其中一个功能模块,需要调用本公司另一个项目组中数据,当时项目经理让我去完成这个项目,我就想到使用httpClient技术来实现这个功能,通过上网查找资料和查阅以前的笔记,首先导入httpClient相关的jar包,通过以上6步连接要调用的项目,开始在做添加时候出现了乱码问题,后来在postMothed中加上编码集设置 postMethod.setRequestHeader(“Content-Type”,“application/x-www-form-urlencoded;charset=utf-8”);后解决了该问题,在文件上传时候应该注意上传的文件名,和要调用的项目中接收的文件名一致。

人事面试问题汇总
1.为什么要离职?

不能损坏上个公司的利益,不能损害自己的形象。

2.薪资多少?

不能说出自己的底线,

3.以前做过的项目?

项目一定与公司的岗位有直接联系,讲解的项目必须大,技术相当;讲解的项目一定要详细;讲能力和优势说出来。

4.说说你的优缺点?

尽量与工作有关的优点,不要把明显的优点说成缺点,少用形容词,缺点不能影响工作,介绍缺点,必须从普遍的缺点方面说出来

5.你能做一个自我介绍?

6.介绍一下你以前的公司?

性质,规模,具体承接哪些项目,不可以损害形象;

7.你对加班有什么看法?
我在上一家公司经常加班。

8.你还有什么问题吗?

必须有问题提出,最新的框架,项目,以及需求

9.你为什么还没有找到合适的岗位?

说明能力与工作不匹配,对于本岗位有客观的认识。

10.谈谈你未来几年的职业规划?

独立负责项目的开发,拥有自己的开发团队,不要提及自己创业开公司。

11.你的业余爱好是什么?

12.你觉得对这个工作感兴趣吗?

不能简单的说感兴趣,应该具体介绍。

13.谈谈你的一个失败的经历?

不可以说没有失败过,说说失败的经历走出来。

14.说说你会在我们工作待多久?

要体现出来,在公司一天,就为工作体现一天的价值。

  1. 简单介绍一下你的缺点?
    答:我的缺点就是缺乏关于这个岗位的工作经验,虽然我知道的知识挺多,但具体这个岗位上面需要什么样子的知识,还得等到我到位之后才可以慢慢积累,

欢迎使用Markdown编辑器


你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。

新的改变

我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:

  1. 全新的界面设计 ,将会带来全新的写作体验;
  2. 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示;
  3. 增加了 图片拖拽 功能,你可以将本地的图片直接拖拽到编辑区域直接展示;
  4. 全新的 KaTeX数学公式 语法;
  5. 增加了支持甘特图的mermaid语法1 功能;
  6. 增加了 多屏幕编辑 Markdown文章功能;
  7. 增加了 焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置 等功能,功能按钮位于编辑区域与预览区域中间;
  8. 增加了 检查列表 功能。

功能快捷键

撤销:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜体:Ctrl/Command + I
标题:Ctrl/Command + Shift + H
无序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
检查列表:Ctrl/Command + Shift + C
插入代码:Ctrl/Command + Shift + K
插入链接:Ctrl/Command + Shift + L
插入图片:Ctrl/Command + Shift + G

合理的创建标题,有助于目录的生成

直接输入1次#,并按下space后,将生成1级标题。
输入2次#,并按下space后,将生成2级标题。
以此类推,我们支持6级标题。有助于使用TOC语法后生成一个完美的目录。

如何改变文本的样式

强调文本 强调文本

加粗文本 加粗文本

标记文本

删除文本

引用文本

H2O is是液体。

210 运算结果是 1024.

插入链接与图片

链接: link.

图片: Alt

带尺寸的图片: Alt

居中的图片: Alt

居中并且带尺寸的图片: Alt

当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。

如何插入一段漂亮的代码片

去博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片.

// An highlighted block
var foo = 'bar';

生成一个适合你的列表

  • 项目
    • 项目
      • 项目
  1. 项目1
  2. 项目2
  3. 项目3
  • 计划任务
  • 完成任务

创建一个表格

一个简单的表格是这么创建的:

项目Value
电脑$1600
手机$12
导管$1

设定内容居中、居左、居右

使用:---------:居中
使用:----------居左
使用----------:居右

第一列第二列第三列
第一列文本居中第二列文本居右第三列文本居左

SmartyPants

SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:

TYPEASCIIHTML
Single backticks'Isn't this fun?'‘Isn’t this fun?’
Quotes"Isn't this fun?"“Isn’t this fun?”
Dashes-- is en-dash, --- is em-dash– is en-dash, — is em-dash

创建一个自定义列表

Markdown
Text-to- HTML conversion tool
Authors
John
Luke

如何创建一个注脚

一个具有注脚的文本。2

注释也是必不可少的

Markdown将文本转换为 HTML

KaTeX数学公式

您可以使用渲染LaTeX数学表达式 KaTeX:

Gamma公式展示 Γ ( n ) = ( n − 1 ) ! ∀ n ∈ N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N Γ(n)=(n1)!nN 是通过欧拉积分

Γ ( z ) = ∫ 0 ∞ t z − 1 e − t d t &ThinSpace; . \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,. Γ(z)=0tz1etdt.

你可以找到更多关于的信息 LaTeX 数学表达式here.

新的甘特图功能,丰富你的文章

Mon 06 Mon 13 Mon 20 已完成 进行中 计划一 计划二 现有任务 Adding GANTT diagram functionality to mermaid
  • 关于 甘特图 语法,参考 这儿,

UML 图表

可以使用UML图表进行渲染。 Mermaid. 例如下面产生的一个序列图::

张三 李四 王五 你好!李四, 最近怎么样? 你最近怎么样,王五? 我很好,谢谢! 我很好,谢谢! 李四想了很长时间, 文字太长了 不适合放在一行. 打量着王五... 很好... 王五, 你怎么样? 张三 李四 王五

这将产生一个流程图。:

链接
长方形
圆角长方形
菱形
  • 关于 Mermaid 语法,参考 这儿,

FLowchart流程图

我们依旧会支持flowchart的流程图:

Created with Raphaël 2.2.0 开始 我的操作 确认? 结束 yes no
  • 关于 Flowchart流程图 语法,参考 这儿.

导出与导入

导出

如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。

导入

如果你想加载一篇你写过的.md文件或者.html文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。


  1. mermaid语法说明 ↩︎

  2. 注脚的解释 ↩︎

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java面试题(仅供参考) 的相关文章

随机推荐

  • 7、AUTOSAR MCAL入门-实战:I/O驱动组

    7 AUTOSAR MCAL入门 实战 xff1a I O驱动组 在第三节中有介绍AUTOSAR 把MCAL 抽象分为4个驱动组 xff0c 分别为 xff1a 微控制器驱动组 xff0c 存储器驱动组 xff0c 通信驱动组 输入 输出驱
  • FreeRTOS学习笔记:FreeRTOS启动方式及流程

    FreeRTOS启动方式及流程 FreeRTOS有两种比较流行的启动方式 1 方式一 xff1a 在main函数中创建所有任务 具体说明 xff1a 在main函数中将硬件初始化 RTOS系统初始化 xff0c 创建所有的任务 xff0c
  • 树莓派4B与Android之缘——树莓派下LineageOS(Android 9)系统开机联网与远程控制

    一 树莓派连接屏幕 1 找到树莓派的micro hdmi口 xff0c 是视频图像的输出口 xff0c 见下图中的MICRO HDMI PORTS 2 连接屏幕 xff08 1 xff09 如果显示屏输入端口是HDMI xff0c 就用mi
  • Deep SDF 、NeuS学习

    DeepSDF Learning Continuous Signed Distance Functions for Shape Representation xff1a 学习用于形状表示的连续有符号距离函数 NeuS Learning Ne
  • layui 引入方式

    layui xff08 谐音 xff1a 类UI 是一款采用自身模块规范编写的前端 UI 框架 xff0c 遵循原生 HTML CSS JS 的书写与组织形式 xff0c 门槛极低 xff0c 拿来即用 其外在极简 xff0c 却又不失饱满
  • ubuntu20.04安装ROS及常见问题

    ubuntu20 04安装ROS及常见问题 一 ubuntu安装参考 xff08 双系统 xff09 1 ios镜像官网下载地址 xff1a https releases ubuntu com ga 61 2 239339907 18418
  • 在jetson xavier nx上配置orbslam3,带稠密重建

    这里写自定义目录标题 主要记录一下踩过的各种坑 xff0c 包括从配置开发板系统到配置orbslam3一条龙服务 xff0c 带cuda加速的opencv3 4 5开发板刷系统将系统移植到M 2硬盘上Sdkmanager安装cuda cud
  • ROS入门教程(五)—— RViz仿真

    上篇文章我们介绍了URDF文件的导出 xff0c 本文将继上文介绍安装完导出URDF文件后 xff0c 如何在机器人操作系统 ROS 中显示 xff0c 并且让它动起来 目录 前言 RViz机器人模型可视化 launch启动RViz配置文件
  • js几种继承

    提示 xff1a 主要是原型链继承 构造函数继承 原型链加构造函数继承 寄生组合式继承 一 原型链继承 子类想要继承父类的属性和方法 xff0c 可以将其原型对象指向父类的实例 xff0c 根据原型链就可以使用到父类的方法和属性 父类 fu
  • C++ 学习(基础语法篇)

    一 基础语法 1 1 C 43 43 简介 C 43 43 是一种静态类型的 编译式的 通用的 大小写敏感的 不规则的编程语言 xff0c 支持过程化编程 面向对象编程和泛型编程 C 43 43 是 C 的一个超集 xff0c 事实上 xf
  • 数据可视化--实验六:层次和网络可视化、文本可视化

    声明 xff1a 本文CSDN作者原创投稿文章 xff0c 未经许可禁止任何形式的转载 xff0c 原文链接 文章目录 概要实验过程Pyecharts实验结果邮件往来网络图职位树图邮件主题词云图 实验结论 概要 学院 xff1a 计算机科学
  • ssh连接windows10拒绝连接

    第一步 xff1a ssh使用的22端口 xff0c 首先确认windows10的22端口是否开启 开启步骤 1 控制面板 gt Windws Defender 防火墙 gt 高级设置 gt 入站规则 gt 新建规则 2 选择端口 gt 下
  • Jetson TX1 学习1 GPIO

    学习过程中为了防止遗忘 以此文字记录 如有错误 多多包涵 怕什么真理无穷 进一寸有一寸的欢喜 胡适 前置内容 xff1a Jetson GPIO 库 学习目标 xff1a 简单控制 Jetson TX1 官方载板 GPIO 引脚 学习内容
  • It was either not specified and/or could not be found for the javaType (java.util.List) : jdbcType

    在使用MyBatis Plus的时候 xff0c 他会将实体类以及表字段自动关联起来 xff0c 但是当我们想要指定额外的一对多关系的时候 xff0c 例如 xff1a 订单保存的时候同时需要保存订单详情列表 xff0c 此时订单与订单详情
  • WSL安装xfce4图像界面,并通过windows远程桌面登陆

    一 下载xorg xorg为X11的一个实现 xff0c xfce4需要 sudo apt install xrog 二 下载xfce4 sudo apt install xfce4 三 下载xrdp xrdp为远程连接软件 xff0c 默
  • linux 线程池 (C语言实现)

    线程池分为三个部分 xff1a 任务队列工作线程 xff0c N个 xff08 任务队列的消费者 xff09 管理者线程 xff0c 1个 主要实现的函数 xff1a 创建线程池线程池添加任务销毁线程池任务函数 xff08 做什么 xff0
  • javascript之异步操作理解---回调函数,async,await以及promise对象

    javascript之异步操作理解 回调函数 xff0c async xff0c await以及promise对象 概述 概述 写在前面 xff1a 虽然平时做项目 xff0c 但是发现自己写的代码还是很烂 最近接触了一个对性能要求比较高的
  • Linux Ubuntu 查看文件大小 查看磁盘大小

    文章目录 1 查看某个文件的信息 xff08 其中大小以字节B为单位 xff09 2 查看文件夹的大小3 查看磁盘分区的大小参考 xff1a 1 查看某个文件的信息 xff08 其中大小以字节B为单位 xff09 span class to
  • 虚拟化管理服务器(手动安装虚拟机,利用脚本命令安装虚拟机,虚拟机的管理,复制,快照)

    实验环境 xff1a 真机的shell 手动安装虚拟机 xff1a 前提 xff1a 镜像文件已经下载好 xff0c 并要知道其所存放的路径 步骤一 xff1a 在真机的shell 中输入virt manager 进入虚拟化管理 步骤二 x
  • java面试题(仅供参考)

    java面试题 仅供参考 框架阶段 概念宝典 1 自我介绍 P2P网贷项目 4 第三个月 基础框架篇 8 一 基础概念篇 8 1 Get和Post的区别 xff1f 8 2 List Set Collection Collections的区