Java 面试知识点解析(七)——Web篇

  • 前言:

在遨游了一番 Java Web 的世界之后,发现了自己的一些缺失,所以就着一篇深度好文:知名互联网公司校招 Java 开发岗面试知识点解析 ,来好好的对 Java 知识点进行复习和学习一番,大部分内容参照自这一篇文章,有一些自己补充的,也算是重新学习一下 Java 吧。

前序文章链接:

Java 面试知识点解析(一)——基础知识篇

Java 面试知识点解析(二)——高并发编程篇

Java 面试知识点解析(三)——JVM篇

Java 面试知识点解析(四)——版本特性篇

Java 面试知识点解析(五)——网络协议篇

Java 面试知识点解析(六)——数据库篇


(一)J2EE 相关知识点

不涉及任何框架,对 J2EE 相关知识点的解析

1)Servlet 的生命周期?

在 Web 容器中,Servlet 主要经历 4 个阶段,如下图:

1. 加载 Servlet:当 Tomcat 第一次访问 Servlet 的时候,Tomcat 会负责创建 Servlet 的实例。

2. 初始化 Servlet:当 Servlet 被实例化之后,Tomcat 会调用 init() 方法来初始化这个对象。

3. 处理服务:当浏览器访问 Servlet 的时候,Servlet 会调用 service() 方法处理请求。

4. 销毁:当 Tomcat 关闭或者检测到 Servlet 要从 Tomcat 删除的时候,会自动调用 destroy() 方法,让该实例所占用的资源释放掉。一个 Servlet 如果长时间不被使用的话,也会被 Tomcat 自动销毁。

  • 简单总结:只要访问 Servlet ,就会调用其对应的 service() 方法,init() 方法只会在第一次访问 Serlvet 的时候才会被调用。

2)Servlet 的请求流程?

  1. 浏览器发出请求: http://localhost:80/xxx1/xxx2 (80端口可以默认不写,因为这是http协议默认的端口,平时我们访问https://www.baidu.com/ 时其实访问的是https://www.baidu.com:80/

  2. 服务器解析请求信息:
    • http:协议名称
    • localhost:访问的是互联网中的哪一台计算机
    • 80:从主机当中找到对应 80 端口的程序 这里即为 Tomcat 服务器
    • /xxx1:当前项目的上下文路径 (即在 server.xml 中配置主机时配置的 path属性
    • /xxx2:当前请求的资源名
  3. 解析 Tomcat 服务器根目录下的 /config/server.xml 文件:
    <Context docBase="D:\javaPros\test\webapp" path="xxx1" />
    判断哪一个<Context />元素的 path属性 属性为 xxx1
    • 若找不到,则返回 404错误
    • 若找到了,则解析该<Context />元素,得到docBase属性,获取当前访问 Web 项目的跟的绝对路径:D:\javaPros\test\webapp
  4. D:\javaPros\test\webapp下的 WEB-INF 下找到 web.xml 文件
    判断 web.xml 文件中是否有 <url-pattern> 的文本内容为 /xxx2
    • 若找不到,则返回 404错误
    • 若找到了,则继续获取该资源对应 Servlet 类的全限名称: xxx.xxx
  5. 判断 Servlet 实例缓存池 中是否有 xxx.xxx 的对象
Map<String,Servlet> cache = ......(Tomcat提供的);
    key:存Servlet类的全限定名称
    value:该Servlet类的对象.
Servlet obj = cache.get("xxx.xxx");
    if(obj==null){
        //Servlet实例缓存中没有该类的对象,第一次.
        GOTO 6:
    }else{
        //有对象,非第一次.
        GOTO 8:
    }
}
  1. 使用反射调用构造器,创建对应的对象
    obj = Class.forName("xxx.xxx").newInstance();
    把当前创建的 Servlet 对象,存放在缓存之中,供给下一次的使用.
    cache.put("xxx.xxx",obj);

  2. 创建 ServletConfig 对象,并调用 init() 方法
    obj.init(config);

  3. 创建 ServletRequest 对象和 ServletResponse 对象,并调用 service()方法
    obj.service(req,resp);

  4. service() 方法中对浏览器作出响应操作。


3)Servlet 是单例的吗?为什么?

Servlet 是单例的,浏览器多次对Servlet的请求,一般情况下,服务器只创建一个Servlet对象,也就是说,Servlet对象一旦创建了,就会驻留在内存中,为后续的请求做服务,直到服务器关闭。


4)GET 和 POST 的区别

要知道,GET 和 POST 都是请求方式

1. GET:

浏览器器地址栏:http://localhost/test.html?name=wmyskxz&sex=male

这里提交了两个参数,一个是name属性值为wmyskxz,另一个是sex属性值为male,这是一种直接的请求方式,在请求资源后面跟上 ? 符号与参数连接,其他的参数使用 & 符号连接。

  • 缺点:
    1.暴露请求信息,不安全
    2.请求信息不能超过1kb,可传输的信息有限,不能上传图片

2. POST:

浏览器地址栏:http://localhost/test.html#

  • 优点:
    1.隐藏了请求信息,较安全(但仍可以通过相关工具访问到数据)
    2.POST 方式没有限制请求的数据大小,可以做图片的上传

5)Tomcat 中如何解决中文乱码问题?

Tomcat 服务器中,接受请求的时候,默认的编码方式为 ISO-8859-1,而该编码方式只占一个字节,不支持中文(两个字节),所以当我们做请求的时候,会出现乱码的问题

解决方案:

1.对乱码使用 ISO-8859-1 解码,转换成byte数组,恢复为二进制
byte[] data = name.getBytes("ISO-8859-1");

2.对byte数组重新进行 UTF-8 编码:
name = new String(data,"UTF-8");
但是这样会出现一个问题,那就是当表单数据太多的时候,这样反复解码-编码,会很繁琐。

终极解决方案:

1.对于 POST 请求:
设置请求的编码方式:request.setCharacterEncoding("UTF-8");
注意:必须在获取第一个参数之前设置,并且该方式只对 POST 方式有效。

2.对于 GET 请求:
重新设置 Tomcat 的编码方式,修改 Tomcat 的配置文件:
Tomcat根目录/conf/server.xml(修改端口的那一行)


6)forward 与 redirect 的区别

1.请求转发(forward)

又叫做直接转发方式,客户端和浏览器只发出一次请求,Servlet、HTML、JSP或其它信息资源,由第二个信息资源响应该请求,在请求对象request中,保存的对象对于每个信息资源是共享的。

比如:从 AServlet 请求转发到 BServlet

  • 语法:
request.getRequestDispatcher(path).forward(request, response);

参数: path,要跳转到的资源路径:上下文路径 / 资源路径

特点:

1.地址栏中的地址【不会】改变,通常看作是服务端的跳转

2.只有一个请求

3.资源是共享的

也就是说在两个 Servlet 中可以共享请求的资源,可以通过request.setAttribute(String var1,Object var2)设置要共享的数据资源,并通过request.getAttribute(String var1);获取传递的资源

4.【可以】访问 WEB-INF 中的资源

WEB-INF 文件夹是 Java Web 应用的默认安全目录,即客户端无法直接访问,只有服务端可以访问的目录。如果想在页面中直接访问其中的文件,必须通过web.xml文件对要访问的文件进行相应映射才能访问。

注意:在实际的开发中,可以把不希望用户直接访问到(通过浏览器输入地址栏)的网页放在文件夹中通过此方式访问。

5.请求转发【不能】跨域访问

所谓的同域,是指域名,协议,端口均相同

2.URl 重定向(redirect)

又叫做间接转发方式(Redirect)实际是两次HTTP请求,服务器端在响应第一次请求的时候,让浏览器再向另外一个URL发出请求,从而达到转发的目的。

比如:从AServlet重定向到BServlet

  • 语法:
response.sendRedirect(String location);

参数:location,转发到的资源路径

特点:

1.地址栏中的地址【会】发生改变,通常看作是客户端跳转

2.有两个请求

3.在两个 Servlet 中不可以共享请求中的数据

4.最终的响应由 BServlet 来决定,和 AServlet 没有关系

5.【不可以】访问 WEB-INF 中的资源

6.请求转发【能】跨域访问

就像是在网页中点开了新的链接一样

  • 总结:URL 重定向相当于是将重定向的资源路径,重新复制到浏览器地址栏中按下回车一样,重新发送一次新的请求。

7)JSP 的执行原理?

当访问一个 JSP 页面时,该页面请求将会讲给服务器中的 JSP 引擎去处理,它负责解释和执行 JSP 页面,每个 JSP 页面在第一次被访问时,JSP 引擎就会将它翻译成一个继承自 org.apache.jasper.runtime.HttpJspBase类的 Servlet 源程序,接着再编译成 class 类文件,再由 Web 容器像调用普通 Servlet 程序一样的方式来装载和解释执行这个由 JSP 页面翻译成的 Servlet 程序。


8)request.getAttribute() 和 request.getParameter() 有何区别?

  1. request.getParameter() 通常用来接收接收表单的get或者post提交过来的参数;而request.getAttribute()一般和setAttribute()搭配使用,只有先set之后才能通过get方法获取到Object类型的数据

  2. getAttribute 返回的是对象,而getParameter 返回的是字符串

  3. getAttribute 和 setAttribute 只是在 web 容器内流转,仅仅是请求处理阶段;而 getParameter 取到的数据是通过容器来获取的。


9)JSP 与 Servlet 的区别?

  1. JSP 实质上就是一个 Servlet。可以理解为,JSP 是编译后的 “Servlet 类”;
  2. JSP 由 HTML 代码和 JSP 标签组成,更擅长页面显示;而 Servlet 更擅长流程控制;
  3. JSP 感觉像是 HTML 中嵌入 Java 代码,而 Servlet 有些像 Java 中嵌入 HTML 代码的意思。

10)JSP 静态包含和动态包含的区别?

(1)静态包含:编译指令包含

<%@include file="被包含的页面的路径"%>

包含的时机:在 JSP 文件被翻译的时候合并在一起,最终翻译得到一个 class文件

(2)动态包含:动作指令包含

<jsp:include page="被包含页面的路径"></jsp:include>

包含的时机:在运行阶段合并代码,最终得到两个 class 文件

(3)动态包含和静态包含的选择:

  • 如果被包含的页面如果是静态页面,那么使用静态包含;
  • 如果被包含的如果是动态页面,那么使用动态包含。

11)JSP 有哪些内置对象?作用分别是什么?

JSP 共有以下 9 个内置的对象:

  1. request:用户端请求,此请求会包含来自 GET/POST 请求的参数;
  2. response:表示一次响应对象;
  3. pageContext:表示当前的 JSP 对象;
  4. session:表示一次会话对象;
  5. application:表示当前应用对象;
  6. out:表示一个输出流对象;
  7. config:表示当前 JSP 的配置对象;
  8. page:表示当前页面;
  9. exception:表示异常对象。

12)JSTL 是什么?优点有哪些?

JSTL(JSP StandardTagLibrary,JSP标准标签库)是一个不断完善的开放源代码的JSP标签库,由四个定制标记库(core、format、xml和sql)和一对通用标记库验证器(ScriptFreeTLV和PermittedTaglibsTLV)组成。优点有:

  1. 在应用程序服务器之间提供了一致的接口,最大程序地提高了WEB应用在各应用服务器之间的移植。

  2. 简化了JSP和WEB应用程序的开发。

  3. 以一种统一的方式减少了JSP中的scriptlet代码数量,可以达到没有任何scriptlet代码的程序。在我们公司的项目中是不允许有任何的scriptlet代码出现在JSP中。

  4. 允许JSP设计工具与WEB应用程序开发的进一步集成。相信不久就会有支持JSTL的IDE开发工具出现。


Cookie 是一种会话技术,用于将用户的信息保存在客户端上。Cookie 英文直接翻译过来就是小甜品,Cookie 的作用呢,通俗的说就是当一个用户通过 HTTP 访问一个服务器时,这个服务器会将一些 Key/Value 键值对返回给客户端浏览器,并给这些数据加上一些限制条件,在条件符合时这个用户下次访问这个服务器时,数据又被完整地带回给服务器。

这个作用就像是你去超市购物时,第一次给你办了一张购物卡,在这个购物卡里存放了一些你的个人信息,下次你再来这个超市的时候,你就只需要带上你的购物卡,直接购物就好了。

Session 技术

Session:会话,从浏览器打开开始,直到浏览器关闭结束,无论在这个网站中访问了多少页面,点击了多少链接,都属于同一个会话。Session 也可以称为会话 Cookie

  • 特点:服务端技术,将数据保存在服务器

  • Cookie 的数据是存放在客户的浏览器上,Session 数据放在服务器上;
  • Cookie 不是很安全,别人可以分析存放在本地的 Cookie 并进行 Cookie 欺骗,如果考虑安全问题则应当使用 Session;
  • Session 会在一定时间内保存在服务器上,当访问增多,会比较占用服务器的资源,所以如果考虑性能问题,则应当使用 Cookie;
  • 单个 Cookie 在客户端的限制是 3k ,就是说一个站点在客户端存放的 Cookie 不能超过 3k。

总结: 将登录信息等重要信息存放为 Session;其他信息如果需要保留,可以存放在 Cookie 中。


14)什么是过滤器?

过滤器就是 Servlet 的高级特性之一,就是一个具有拦截/过滤功能的一个东西,在生活中过滤器可以是香烟滤嘴,滤纸,净水器,空气净化器等,在 Web 中仅仅是一个实现了 Filter 接口的 Java 类而已。

  • 特点:双向,拦截请求,拦截响应

  • 作用:
    过滤器可以对所有的请求或者响应做拦截操作

15)为什么在 Web 开发中需要用到过滤器?

  • 问题:为什么非得使用过滤器,我直接在 Servlet 中作判断不行吗?
  • 开发遵循的原则:
    1.DRY原则(Don't Reeat Yourself,不要重复你自己):重复,意味着维护的成本很高。
    2.责任分离原则:谁擅长什么功能就做什么功能,Servlet 擅长的是逻辑而不是处理请求

举一个实际的例子:(处理 POST 请求中文编码的问题)

  • Web 中过滤器的作用:
    1.可以在请求资源之前设置请求的编码
    2.可以进行登录校验
    3.可以进行请求参数的内容的过滤
    4.数据压缩 / 数据加密 / 数据格式的转换
    5.可以设置浏览器相关的数据

16)MVC 模式?

MVC模式(Model-View-Controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller):

  • Controller——负责转发请求,对请求进行处理
  • View——负责界面显示
  • Model——业务功能编写(例如算法实现)、数据库设计以及数据存取操作实现

在JSP/Servlet开发的软件系统中,这三个部分的描述如下所示:

1.Web浏览器发送HTTP请求到服务端,被Controller(Servlet)获取并进行处理(例如参数解析、请求转发)
2.Controller(Servlet)调用核心业务逻辑——Model部分,获得结果
3.Controller(Servlet)将逻辑处理结果交给View(JSP),动态输出HTML内容
4.动态生成的HTML内容返回到浏览器显示

MVC模式在Web开发中的好处是非常明显,它规避了JSP与Servlet各自的短板,Servlet只负责业务逻辑而不会通过out.append()动态生成HTML代码;JSP中也不会充斥着大量的业务代码。这大大提高了代码的可读性和可维护性。


(二)框架相关知识

由于我没有接触和学习过 Hibernate 和 Struts 这两个框架,所以细节方面的东西请读者自行收集...

1)什么是框架?

框架是指完成一定功能的半成品。

框架能够帮助我们完成的是:项目的整体框架、一些基础功能、规定了类和对象如何创建,如何协作等,当我们开发一个项目时,框架帮助我们完成了一部分功能,我们自己再完成一部分,那这个项目就完成了。


2)什么是 Spring ?

  1. Spring 是一个轻量级的 DI / IoC 和 AOP 容器的开源框架,来源于 Rod Johnson 在其著作《Expert one on one J2EE design and development》中阐述的部分理念和原型衍生而来。

  2. Spring 提倡以 “最少侵入” 的方式来管理应用中的代码,这意味着我们可以随时安装或者卸载 Spring

  • 适用范围:任何 Java 应用
  • Spring 的根本使命:简化 Java 开发

3)什么是非侵入式设计?

从框架的角度可以理解为:无需继承框架提供的任何类
这样我们在更换框架时,之前写过的代码几乎可以继续使用。


4)Spring 有什么优势?

  • 低侵入 / 低耦合 (降低组件之间的耦合度,实现软件各层之间的解耦)
  • 声明式事务管理(基于切面和惯例)
  • 方便集成其他框架(如MyBatis、Hibernate)
  • 降低 Java 开发难度
  • Spring 框架中包括了 J2EE 三层的每一层的解决方案(一站式)

Spring 的框架结构

  • Data Access/Integration层包含有JDBC、ORM、OXM、JMS和Transaction模块。
  • Web层包含了Web、Web-Servlet、WebSocket、Web-Porlet模块。
  • AOP模块提供了一个符合AOP联盟标准的面向切面编程的实现。
  • Core Container(核心容器):包含有Beans、Core、Context和SpEL模块。
  • Test模块支持使用JUnit和TestNG对Spring组件进行测试。

5)Spring IoC 和 DI 分别是什么?

Spring IoC

IoC:Inverse of Control(控制反转),读作 “反转控制”,更好理解,不是什么技术,而是一种设计思想,就是将原本在程序中手动创建对象的控制权,交由Spring框架来管理。

  • 正控:若要使用某个对象,需要自己去负责对象的创建
  • 反控:若要使用某个对象,只需要从 Spring 容器中获取需要使用的对象,不关心对象的创建过程,也就是把创建对象的控制权反转给了Spring框架
  • 好莱坞法则:Don’t call me ,I’ll call you

为了便于理解我们这里举一个鲜明的例子:

在现实生活中,人们要用到一样东西的时候,第一反应就是去找到这件东西,比如想喝新鲜橙汁,在没有饮品店的日子里,最直观的做法就是:买果汁机、买橙子,然后准备开水。值得注意的是:这些都是你自己“主动”创造的过程,也就是说一杯橙汁需要你自己创造。

然而到了今时今日,由于饮品店的盛行,当我们想喝橙汁时,第一想法就转换成了找到饮品店的联系方式,通过电话等渠道描述你的需要、地址、联系方式等,下订单等待,过一会儿就会有人送来橙汁了。

请注意你并没有“主动”去创造橙汁,橙汁是由饮品店创造的,而不是你,然而也完全达到了你的要求,甚至比你创造的要好上那么一些。

  • 总结: 这就是一种控制反转的理念,上述的例子已经很好的说明了问题,我们再来描述一下控制反转的概念:控制反转是一种通过描述(在 Java 中可以是 XML 或者注解)并通过第三方(Spring)去产生或获取特定对象的方式。
  • 好处: ① 降低对象之间的耦合;② 我们不需要理解一个类的具体实现,只需要知道它有什么用就好了(直接向 IoC 容器拿)

DI:Dependency Injection(依赖注入)

指 Spring 创建对象的过程中,将对象依赖属性(简单值,集合,对象)通过配置设值给该对象

两者的区别

IoC 和 DI 其实是同一个概念的不同角度描述,DI 相对 IoC 而言,明确描述了 “被注入对象依赖 IoC 容器配置依赖对象”

你也可以简单的理解为:IoC 是目的,是一种思想,而 DI 是手段,是一种设计模式。


6)BeanFactory 和 ApplicationContext 的区别

1.BeanFactory:

是Spring中最底层的接口,只提供了最简单的IoC功能,负责配置,创建和管理bean。在应用中,一般不使用 BeanFactory,而推荐使ApplicationContext(应用上下文),原因如下。

2.ApplicationContext:

⑴. 继承了 BeanFactory,拥有了基本的 IoC 功能;
⑵. 除此之外,ApplicationContext 还提供了以下功能:
① 支持国际化;② 支持消息机制;③ 支持统一的资源加载;④ 支持AOP功能;

  • 注意: ApplicationContext 和 BeanFactory 相比,最主要的区别在于 BeanFactory 是延迟加载,举个例子:如果 Bean 没有完全注入,BeanFactory 加载后,会在你第一次调用 getBean 方法才会抛出异常;而 ApplicationContext 会在初始化的时候就加载并且检查,这样的好处是可以及时检查依赖是否完全注入;所以通常我们会选择 ApplicationContext。

7)IoC 是如何实现的

最后我们简单说说IoC是如何实现的。想象一下如果我们自己来实现这个依赖注入的功能,我们怎么来做? 无外乎:

  1. 读取标注或者配置文件,看看JuiceMaker依赖的是哪个Source,拿到类名
  2. 使用反射的API,基于类名实例化对应的对象实例
  3. 将对象实例,通过构造函数或者 setter,传递给 JuiceMaker

我们发现其实自己来实现也不是很难,Spring实际也就是这么做的。这么看的话其实IoC就是一个工厂模式的升级版!当然要做一个成熟的IoC框架,还是非常多细致的工作要做,Spring不仅提供了一个已经成为业界标准的Java IoC框架,还提供了更多强大的功能,所以大家就别去造轮子啦!希望了解IoC更多实现细节不妨通过学习Spring的源码来加深理解!

引用地址:这里


8)Spring 配置 Bean 有几种方式?

在 Spring 中提供了 3 种方法进行配置:

  • 在 XML 文件中显式配置
  • 在 Java 的接口和类中实现配置
  • 隐式 Bean 的发现机制和自动装配原则

方式选择的原则

在现实的工作中,这 3 种方式都会被用到,并且在学习和工作之中常常混合使用,所以这里给出一些关于这 3 种优先级的建议:

1.最优先:通过隐式 Bean 的发现机制和自动装配的原则。
基于约定由于配置的原则,这种方式应该是最优先的

  • 好处:减少程序开发者的决定权,简单又不失灵活。

2.其次:Java 接口和类中配置实现配置
在没有办法使用自动装配原则的情况下应该优先考虑此类方法

  • 好处:避免 XML 配置的泛滥,也更为容易。
  • 典型场景:一个父类有多个子类,比如学生类有两个子类,一个男学生类和女学生类,通过 IoC 容器初始化一个学生类,容器将无法知道使用哪个子类去初始化,这个时候可以使用 Java 的注解配置去指定。

3.最后:XML 方式配置
在上述方法都无法使用的情况下,那么也只能选择 XML 配置的方式。

  • 好处:简单易懂(当然,特别是对于初学者)
  • 典型场景:当使用第三方类的时候,有些类并不是我们开发的,我们无法修改里面的代码,这个时候就通过 XML 的方式配置使用了。

9)介绍一下 Spring AOP

AOP 即 Aspect Oriented Program 面向切面编程

首先,在面向切面编程的思想里面,把功能分为核心业务功能,和周边功能。

  • 所谓的核心业务,比如登陆,增加数据,删除数据都叫核心业务
  • 所谓的周边功能,比如性能统计,日志,事务管理等等

周边功能在 Spring 的面向切面编程AOP思想里,即被定义为切面

在面向切面编程AOP的思想里面,核心业务功能和切面功能分别独立进行开发,然后把切面功能和核心业务功能 "编织" 在一起,这就叫 AOP

还是来举一个鲜明的例子:

在上面的例子中,包租婆的核心业务就是签合同,收房租,那么这就够了,灰色框起来的部分都是重复且边缘的事,交给中介商就好了,这就是 AOP 的一个思想:让关注点代码与业务代码分离!


10)Spring 中 Bean 的作用域

在默认的情况下,Spring IoC 容器只会对一个 Bean 创建一个实例,但有时候,我们希望能够通过 Spring IoC 容器获取多个实例,我们可以通过 @Scope 注解或者 <bean> 元素中的 scope 属性来设置,例如:

// XML 中设置作用域
<bean id="" class="" scope="prototype" />
// 使用注解设置作用域
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

Spring 提供了 5 种作用域,它会根据情况来决定是否生成新的对象:

作用域类别 描述
singleton(单例) 在Spring IoC容器中仅存在一个Bean实例 (默认的scope)
prototype(多例) 每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时 ,相当于执行new XxxBean():不会在容器启动时创建对象
request(请求) 用于web开发,将Bean放入request范围 ,request.setAttribute("xxx") , 在同一个request 获得同一个Bean
session(会话) 用于web开发,将Bean 放入Session范围,在同一个Session 获得同一个Bean
globalSession(全局会话) 一般用于 Porlet 应用环境 , 分布式系统存在全局 session 概念(单点登录),如果不是 porlet 环境,globalSession 等同于 Session

在开发中主要使用 scope="singleton"scope="prototype"对于MVC中的Action使用prototype类型,其他使用singleton,Spring容器会管理 Action 对象的创建,此时把 Action 的作用域设置为 prototype.

扩展阅读:@Profile 注解条件化装配 Bean


11)Spring 面试问答 Top 25

更多戳这里:Spring面试问答Top 25


12)Spring MVC 的请求流程

每当用户在 Web 浏览器中点击链接或者提交表单的时候,请求就开始工作了,像是邮递员一样,从离开浏览器开始到获取响应返回,它会经历很多站点,在每一个站点都会留下一些信息同时也会带上其他信息,下图为 Spring MVC 的请求流程:

第一站:DispatcherServlet

从请求离开浏览器以后,第一站到达的就是 DispatcherServlet,看名字这是一个 Servlet,通过 J2EE 的学习,我们知道 Servlet 可以拦截并处理 HTTP 请求,DispatcherServlet 会拦截所有的请求,并且将这些请求发送给 Spring MVC 控制器。

<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <!-- 拦截所有的请求 -->
    <url-pattern>/</url-pattern>
</servlet-mapping>
  • DispatcherServlet 的任务就是拦截请求发送给 Spring MVC 控制器。

第二站:处理器映射(HandlerMapping)

  • 问题:典型的应用程序中可能会有多个控制器,这些请求到底应该发给哪一个控制器呢?

所以 DispatcherServlet 会查询一个或多个处理器映射来确定请求的下一站在哪里,处理器映射会根据请求所携带的 URL 信息来进行决策,例如上面的例子中,我们通过配置 simpleUrlHandlerMapping 来将 /hello 地址交给 helloController 处理:

<bean id="simpleUrlHandlerMapping"
      class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="mappings">
        <props>
            <!-- /hello 路径的请求交给 id 为 helloController 的控制器处理-->
            <prop key="/hello">helloController</prop>
        </props>
    </property>
</bean>
<bean id="helloController" class="controller.HelloController"></bean>

第三站:控制器

一旦选择了合适的控制器, DispatcherServlet 会将请求发送给选中的控制器,到了控制器,请求会卸下其负载(用户提交的请求)等待控制器处理完这些信息:

public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {
    // 处理逻辑
    ....
}

第四站:返回 DispatcherServlet

当控制器在完成逻辑处理后,通常会产生一些信息,这些信息就是需要返回给用户并在浏览器上显示的信息,它们被称为模型(Model)。仅仅返回原始的信息时不够的——这些信息需要以用户友好的方式进行格式化,一般会是 HTML,所以,信息需要发送给一个视图(view),通常会是 JSP。

控制器所做的最后一件事就是将模型数据打包,并且表示出用于渲染输出的视图名(逻辑视图名)。它接下来会将请求连同模型和视图名发送回 DispatcherServlet。

public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {
    // 处理逻辑
    ....
    // 返回给 DispatcherServlet
    return mav;
}

第五站:视图解析器

这样以来,控制器就不会和特定的视图相耦合,传递给 DispatcherServlet 的视图名并不直接表示某个特定的 JSP。(实际上,它甚至不能确定视图就是 JSP)相反,它传递的仅仅是一个逻辑名称,这个名称将会用来查找产生结果的真正视图。

DispatcherServlet 将会使用视图解析器(view resolver)来将逻辑视图名匹配为一个特定的视图实现,它可能是也可能不是 JSP

上面的例子是直接绑定到了 index.jsp 视图

第六站:视图

既然 DispatcherServlet 已经知道由哪个视图渲染结果了,那请求的任务基本上也就完成了。

它的最后一站是视图的实现,在这里它交付模型数据,请求的任务也就完成了。视图使用模型数据渲染出结果,这个输出结果会通过响应对象传递给客户端。

<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8" isELIgnored="false"%>

<h1>${message}</h1>

更多 Spring-MVC 内容:Spring MVC【入门】就这一篇


13)什么是 ORM?

对象关系映射(Object-Relational Mapping,简称ORM)是一种为了解决程序的面向对象模型与数据库的关系模型互不匹配问题的技术;

简单的说,ORM是通过使用描述对象和数据库之间映射的元数据(在Java中可以用XML或者是注解),将程序中的对象自动持久化到关系数据库中或者将关系数据库表中的行转换成Java对象,其本质上就是将数据从一种形式转换到另外一种形式。


14)为什么要使用 MyBatis ?

在我们传统的 JDBC 中,我们除了需要自己提供 SQL 外,还必须操作 Connection、Statment、ResultSet,不仅如此,为了访问不同的表,不同字段的数据,我们需要些很多雷同模板化的代码,闲的繁琐又枯燥。

而我们在使用了 MyBatis 之后,只需要提供 SQL 语句就好了,其余的诸如:建立连接、操作 Statment、ResultSet,处理 JDBC 相关异常等等都可以交给 MyBatis 去处理,我们的关注点于是可以就此集中在 SQL 语句上,关注在增删改查这些操作层面上。

并且 MyBatis 支持使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。


15)MyBatis 中占位符 #$ 的区别

区别如下:

  1. #符号将传入的数据都当做一个字符串,会对自动传入的数据加一个双引号
  2. $符号将传入的数据直接显示生成SQL中。
  3. #符号存在预编译的过程,,对问号赋值,防止SQL注入。
  4. $符号是直译的方式,一般用在orderby {列名} 语句中。
  5. 能用#号就不要用$符号

16)MyBatis 缓存结构

在 Web 系统中,最重要的操作就是查询数据库中的数据。但是有些时候查询数据的频率非常高,这是很耗费数据库资源的,往往会导致数据库查询效率极低,影响客户的操作体验。于是我们可以将一些变动不大且访问频率高的数据,放置在一个缓存容器中,用户下一次查询时就从缓存容器中获取结果。

  • MyBatis 拥有自己的缓存结构,可以用来缓解数据库压力,加快查询速度。
  • MyBatis 一级缓存是一个 SqlSession 级别,同一个 SqlSession 只能访问自己的一级缓存的数据
  • 二级缓存是跨sqlSession,是 mapper 级别的缓存,对于 mapper 级别的缓存不同的sqlsession是可以共享的。

更多深入MyBatis的内容戳这里:MyBatis(2)——MyBatis 深入学习


17)MyBatis 与 Spring 整合

戳这里:MyBatis 与 Spring 整合


18)IDEA 整合 SSM 框架学习

戳这里IDEA 整合 SSM 框架学习


19)MVC 三种模式

在早期 Java Web 的开发中,统一把显示层、控制层、数据层的操作全部交给 JSP 或者 JavaBean 来进行处理,我们称之为 Model1:

  • 出现的弊端:
  • JSP 和 Java Bean 之间严重耦合,Java 代码和 HTML 代码也耦合在了一起
  • 要求开发者不仅要掌握 Java ,还要有高超的前端水平
  • 前端和后端相互依赖,前端需要等待后端完成,后端也依赖前端完成,才能进行有效的测试
  • 代码难以复用

正因为上面的种种弊端,所以很快这种方式就被 Servlet + JSP + Java Bean 所替代了,早期的 MVC 模型(Model2)就像下图这样:

首先用户的请求会到达 Servlet,然后根据请求调用相应的 Java Bean,并把所有的显示结果交给 JSP 去完成,这样的模式我们就称为 MVC 模式。

  • M 代表 模型(Model)
    模型是什么呢? 模型就是数据,就是 dao,bean
  • V 代表 视图(View)
    视图是什么呢? 就是网页, JSP,用来展示模型中的数据
  • C 代表 控制器(controller)
    控制器是什么? 控制器的作用就是把不同的数据(Model),显示在不同的视图(View)上,Servlet 扮演的就是这样的角色。

扩展阅读:Web开发模式

Spring MVC 的架构

为解决持久层中一直未处理好的数据库事务的编程,又为了迎合 NoSQL 的强势崛起,Spring MVC 给出了方案:

传统的模型层被拆分为了业务层(Service)和数据访问层(DAO,Data Access Object)。在 Service 下可以通过 Spring 的声明式事务操作数据访问层,而在业务层上还允许我们访问 NoSQL ,这样就能够满足异军突起的 NoSQL 的使用了,它可以大大提高互联网系统的性能。

  • 特点:
    结构松散,几乎可以在 Spring MVC 中使用各类视图
    松耦合,各个模块分离
    与 Spring 无缝集成

20)分页?

戳这里:Java Web -【分页功能】详解


21)什么是 Spring Boot ?

  • 它使用 “习惯优于配置” (项目中存在大量的配置,此外还内置一个习惯性的配置,让你无须)的理念让你的项目快速运行起来。
  • 它并不是什么新的框架,而是默认配置了很多框架的使用方式,就像 Maven 整合了所有的 jar 包一样,Spring Boot 整合了所有框架(引自:springboot(一):入门篇——纯洁的微笑

22)使用 Spring Boot 有什么好处?

回顾我们之前的 SSM 项目,搭建过程还是比较繁琐的,需要:

  • 1)配置 web.xml,加载 spring 和 spring mvc
  • 2)配置数据库连接、配置日志文件
  • 3)配置家在配置文件的读取,开启注解
  • 4)配置mapper文件
  • .....

而使用 Spring Boot 来开发项目则只需要非常少的几个配置就可以搭建起来一个 Web 项目,并且利用 IDEA 可以自动生成生成,这简直是太爽了...

  • 划重点:简单、快速、方便地搭建项目;对主流开发框架的无配置集成;极大提高了开发、部署效率。

Spring Boot 由于笔者还没有深入学习..所以细节部分请读者自行收集...


欢迎转载,转载请注明出处!
简书ID:@我没有三颗心脏
github:wmyskxz
欢迎关注公众微信号:wmyskxz_javaweb
分享自己的Java Web学习之路以及各种Java学习资料

posted @ 2018-05-22 10:25 我没有三颗心脏 阅读(...) 评论(...) 编辑 收藏