精华内容
下载资源
问答
  • 前后端强依赖,后端必须要等前端的HTML开发好才能套转换成JSP。如果需求变更,前端HTML要改,后端 JSP也要跟着变, 这是件紧紧牵绊的事,使得开发效率降低。 3. 产品交付时,要将前后端代码全部进行打包,部署到同一...

    传统系统架构:
    1 前台工程师负责编写HTML页面,完成前端页面设计。
    2 后端工程师使用模板技术将HTML页面代码转换为 JSP 页面,同时内嵌后端代码 (如Java);
    前后端强依赖,后端必须要等前端的HTML开发好才能套转换成JSP。如果需求变更,前端HTML要改,后端
    JSP也要跟着变, 这是件紧紧牵绊的事,使得开发效率降低。
    3. 产品交付时,要将前后端代码全部进行打包,部署到同一服务器上,或者进行简单的动静态分离部署。
    在这里插入图片描述
    前后端分离架构:

    1. 前后端约定好API接口&数据&参数
    2. 前后端并行开发
      前端工程师只需要编写HTM页面,通过HTTP请求调用后端提供的接口服务即可。
      后端只要愉快的开发接口就行了。
      无强依赖,如果需求变更,只要接口和参数不变,就不用两边都修改代码,开发效率高。
    3. 除了开发阶段分离、在运行期前后端资源也会进行分离部署。
      在这里插入图片描述
      前后端分离已成为互联网项目开发的业界标准使用方式。传统的前后端混合开发模式,虽然久经考验,到现在依然还是能够支撑起应用的开发。但是放眼未来,社会分工更加精细化,前后端分离开发的精细化也是必然趋势。并且前后端分离会为以后的大型分布式架构、微服务架构、多端化服务(多种客户端,例如:浏览器,安卓,IOS, 车载终端等等)打下坚实的基础。

    具体前后端分离是如何实现的呢?举例:

    在前端和后端开发之前,会有一个api开发文档,不管是前端还是后端都会基于这个aoi文档进行开发。

    前台就只需要开发它的html页面即可,因为要渲染数据,前台开发工程师就需要参考api开发文档,比如这个api开发文档有一个功能要调用emp/list方法获取列表数据,同时这个方法要传入什么参数,返回什么数据都会写。对应的前台发送ajax请求为文档上的请求,参数返回值都基于文档,最后在将返回的数据渲染到页面当中。那没有经过真正的后台处理,数据是如何返回的呢?

    mock.js就能处理这种问题。模拟接口数据,不需要等待后台开发人员开发的接口进行测试。

    而后台开发人员就仅仅关注后台接口的开发,而这个接口开发也是需要参考这个api开发文档,后台开发工程师就不需要关注,接口返回的数据如何渲染到html页面当中。

    当前后端都开发完成之后,就可以进行联调。最终上线的时候,前台部署全台项目,后台部署后台项目。

    为什么要前后端分离?有什么优缺点
    一、前戏
    前后端分离已成为互联网项目开发的业界标准使用方式,通过nginx+tomcat的方式(也可以中间加一个nodejs)有效的进行解耦,并且前后端分离会为以后的大型分布式架构、弹性计算架构、微服务架构、多端化服务(多种客户端,例如:浏览器,车载终端,安卓,IOS等等)打下坚实的基础。这个步骤是系统架构从猿进化成人的必经之路。

    核心思想是前端html页面通过ajax调用后端的restuful api接口并使用json数据进行交互。

    在互联网架构中,名词解释:

    Web服务器:一般指像nginx,apache这类的服务器,他们一般只能解析静态资源。

    应用服务器:一般指像tomcat,jetty,resin这类的服务器可以解析动态资源也可以解析静态资源,但解析静态资源的能力没有web服务器好。

    一般都是只有web服务器才能被外网访问,应用服务器只能内网访问。

    二、术业有专攻(开发人员分离)

    以前的JavaWeb项目大多数都是java程序员又当爹又当妈,又搞前端,又搞后端。

    随着时代的发展,渐渐的许多大中小公司开始把前后端的界限分的越来越明确,前端工程师只管前端的事情,后端工程师只管后端的事情。正所谓术业有专攻,一个人如果什么都会,那么他毕竟什么都不精。

    大中型公司需要专业人才,小公司需要全才,但是对于个人职业发展来说,我建议是分开。

    1、对于后端java工程师:

    把精力放在java基础,设计模式,jvm原理,spring+springmvc原理及源码,linux,mysql事务隔离与锁机制,mongodb,http/tcp,多线程,分布式架构,弹性计算架构,微服务架构,java性能优化,以及相关的项目管理等等。

    后端追求的是:三高(高并发,高可用,高性能),安全,存储,业务等等。

    2、对于前端工程师:

    把精力放在html5,css3,jquery,angularjs,bootstrap,reactjs,vuejs,webpack,less/sass,gulp,nodejs,Google V8引擎,javascript多线程,模块化,面向切面编程,设计模式,浏览器兼容性,性能优化等等。

    前端追求的是:页面表现,速度流畅,兼容性,用户体验等等。

    术业有专攻,这样你的核心竞争力才会越来越高,正所谓你往生活中投入什么,生活就会反馈给你什么。并且两端的发展都越来越高深,你想什么都会,那你毕竟什么都不精。

    通过将team分成前后端team,让两边的工程师更加专注各自的领域,独立治理,然后构建出一个全栈式的精益求精的team。

    三、原始人时代(各种耦合)

    几曾何时,我们的JavaWeb项目都是使用了若干后台框架,springmvc/struts + spring + spring jdbc/hibernate/mybatis 等等。

    大多数项目在java后端都是分了三层,控制层,业务层,持久层。控制层负责接收参数,调用相关业务层,封装数据,以及路由&渲染到jsp页面。然后jsp页面上使用各种标签或者手写java表达式将后台的数据展现出来,玩的是MVC那套思路。

    我们先看这种情况:需求定完了,代码写完了,测试测完了,然后呢?要发布了吧?你需要用maven或者eclipse等工具把你的代码打成一个war包,然后把这个war包发布到你的生产环境下的web容器里,对吧?

    发布完了之后,你要启动你的web容器,开始提供服务,这时候你通过配置域名,dns等等相关,你的网站就可以访问了(假设你是个网站)。那我们来看,你的前后端代码是不是全都在那个war包里?包括你的js,css,图片,各种第三方的库,对吧?

    好,下面在浏览器中输入你的网站域名(www.xxx.com),之后发生了什么?(这个问题也是很多公司的面试题)我捡干的说了啊,基础不好的童鞋请自己去搜。

    浏览器在通过域名通过dns服务器找到你的服务器外网ip,将http请求发送到你的服务器,在tcp3次握手之后(http下面是tcp/ip),通过tcp协议开始传输数据,你的服务器得到请求后,开始提供服务,接收参数,之后返回你的应答给浏览器,浏览器再通过content-type来解析你返回的内容,呈现给用户。

    那么我们来看,我们先假设你的首页中有100张图片,此时,用户的看似一次http请求,其实并不是一次,用户在第一次访问的时候,浏览器中不会有缓存,你的100张图片,浏览器要连着请求100次http请求(有人会跟我说http长连短连的问题,不在这里讨论),你的服务器接收这些请求,都需要耗费内存去创建socket来玩tcp传输

    四、JSP的痛点

    以前的javaWeb项目大多数使用jsp作为页面层展示数据给用户,因为流量不高,因此也没有那么苛刻的性能要求,但现在是大数据时代,对于互联网项目的性能要求是越来越高,因此原始的前后端耦合在一起的架构模式已经逐渐不能满足我们,因此我们需要需找一种解耦的方式,来大幅度提升我们的负载能力。

    1、动态资源和静态资源全部耦合在一起,服务器压力大,因为服务器会收到各种http请求,例如css的http请求,js的,图片的等等。一旦服务器出现状况,前后台一起玩完,用户体验极差。

    2、UI出好设计图后,前端工程师只负责将设计图切成html,需要由java工程师来将html套成jsp页面,出错率较高(因为页面中经常会出现大量的js代码),修改问题时需要双方协同开发,效率低下。

    3、jsp必须要在支持java的web服务器里运行(例如tomcat,jetty,resin等),无法使用nginx等(nginx据说单实例http并发高达5w,这个优势要用上),性能提不上来。

    4、第一次请求jsp,必须要在web服务器中编译成servlet,第一次运行会较慢。

    5、每次请求jsp都是访问servlet再用输出流输出的html页面,效率没有直接使用html高(是每次哟,亲~)。

    6、jsp内有较多标签和表达式,前端工程师在修改页面时会捉襟见肘,遇到很多痛点。

    7、如果jsp中的内容很多,页面响应会很慢,因为是同步加载。

    8、需要前端工程师使用java的ide(例如eclipse),以及需要配置各种后端的开发环境,你们有考虑过前端工程师的感受吗。

    基于上述的一些痛点,我们应该把整个项目的开发权重往前移,实现前后端真正的解耦!

    五、开发模式

    以前老的方式是:

    1、产品经历/领导/客户提出需求

    2、UI做出设计图

    3、前端工程师做html页面

    4、后端工程师将html页面套成jsp页面(前后端强依赖,后端必须要等前端的html做好才能套jsp。如果html发生变更,就更痛了,开发效率低)

    5、集成出现问题

    6、前端返工

    7、后端返工

    8、二次集成

    9、集成成功

    10、交付

    新的方式是:

    1、产品经历/领导/客户提出需求

    2、UI做出设计图

    3、前后端约定接口&数据&参数

    4、前后端并行开发(无强依赖,可前后端并行开发,如果需求变求变更,只要接口&参数不变,就不用两边都修改代码,开发效率高)

    5、前后端集成

    6、前端页面调整

    7、集成成功

    8、交付

    六、请求方式

    以前老的方式是:

    1、客户端请求

    2、服务端的servlet或controller接收请求(后端控制路由与渲染页面,整个项目开发的权重大部分在后端)

    3、调用service,dao代码完成业务逻辑

    4、返回jsp

    5、jsp展现一些动态的代码

    新的方式是:

    1、浏览器发送请求

    2、直接到达html页面(前端控制路由与渲染页面,整个项目开发的权重前移)

    3、html页面负责调用服务端接口产生数据(通过ajax等等,后台返回json格式数据,json数据格式因为简洁高效而取代xml)

    4、填充html,展现动态效果,在页面上进行解析并操作DOM。

    总结一下新的方式的请求步骤:

    大量并发浏览器请求—>web服务器集群(nginx)—>应用服务器集群(tomcat)—>文件/数据库/缓存/消息队列服务器集群

    同时又可以玩分模块,还可以按业务拆成一个个的小集群,为后面的架构升级做准备。

    七、前后分离的优势

    1、可以实现真正的前后端解耦,前端服务器使用nginx。前端/WEB服务器放的是css,js,图片等等一系列静态资源(甚至你还可以css,js,图片等资源放到特定的文件服务器,例如阿里云的oss,并使用cdn加速),前端服务器负责控制页面引用&跳转&路由,前端页面异步调用后端的接口,后端/应用服务器使用tomcat(把tomcat想象成一个数据提供者),加快整体响应速度。(这里需要使用一些前端工程化的框架比如nodejs,react,router,react,redux,webpack)

    2、发现bug,可以快速定位是谁的问题,不会出现互相踢皮球的现象。页面逻辑,跳转错误,浏览器兼容性问题,脚本错误,页面样式等问题,全部由前端工程师来负责。接口数据出错,数据没有提交成功,应答超时等问题,全部由后端工程师来解决。双方互不干扰,前端与后端是相亲相爱的一家人。

    3、在大并发情况下,我可以同时水平扩展前后端服务器,比如淘宝的一个首页就需要2000+台前端服务器做集群来抗住日均多少亿+的日均pv。(去参加阿里的技术峰会,听他们说他们的web容器都是自己写的,就算他单实例抗10万http并发,2000台是2亿http并发,并且他们还可以根据预知洪峰来无限拓展,很恐怖,就一个首页。。。)

    4、减少后端服务器的并发/负载压力。除了接口以外的其他所有http请求全部转移到前端nginx上,接口的请求调用tomcat,参考nginx反向代理tomcat。且除了第一次页面请求外,浏览器会大量调用本地缓存。

    5、即使后端服务暂时超时或者宕机了,前端页面也会正常访问,只不过数据刷不出来而已。

    6、也许你也需要有微信相关的轻应用,那样你的接口完全可以共用,如果也有app相关的服务,那么只要通过一些代码重构,也可以大量复用接口,提升效率。(多端应用)

    7、页面显示的东西再多也不怕,因为是异步加载。

    8、nginx支持页面热部署,不用重启服务器,前端升级更无缝。

    9、增加代码的维护性&易读性(前后端耦在一起的代码读起来相当费劲)。

    10、提升开发效率,因为可以前后端并行开发,而不是像以前的强依赖。

    11、在nginx中部署证书,外网使用https访问,并且只开放443和80端口,其他端口一律关闭(防止黑客端口扫描),内网使用http,性能和安全都有保障。

    12、前端大量的组件代码得以复用,组件化,提升开发效率,抽出来!

    八、注意事项

    1、在开需求会议的时候,前后端工程师必须全部参加,并且需要制定好接口文档,后端工程师要写好测试用例(2个维度),不要让前端工程师充当你的专职测试,推荐使用chrome的插件postman或soapui或jmeter,service层的测试用例拿junit写。ps:前端也可以玩单元测试吗?

    2、上述的接口并不是java里的interface,说白了调用接口就是调用你controler里的方法。

    3、加重了前端团队的工作量,减轻了后端团队的工作量,提高了性能和可扩展性。

    4、我们需要一些前端的框架来解决类似于页面嵌套,分页,页面跳转控制等功能。(上面提到的那些前端框架)。

    5、如果你的项目很小,或者是一个单纯的内网项目,那你大可放心,不用任何架构而言,但是如果你的项目是外网项目,呵呵哒。

    6、 以前还有人在使用类似于velocity/freemarker等模板框架来生成静态页面,仁者见仁智者见智。

    7、这篇文章主要的目的是说jsp在大型外网java web项目中被淘汰掉,可没说jsp可以完全不学,对于一些学生朋友来说,jsp/servlet等相关的java web基础还是要掌握牢的,不然你以为springmvc这种框架是基于什么来写的?

    8、如果页面上有一些权限等等相关的校验,那么这些相关的数据也可以通过ajax从接口里拿。

    9、对于既可以前端做也可以后端做的逻辑,我建议是放到前端,为什么?因为你的逻辑需要计算资源进行计算,如果放到后端去run逻辑,则会消耗带宽&内存&cpu等等计算资源,你要记住一点就是服务端的计算资源是有限的,而如果放到前端,使用的是客户端的计算资源,这样你的服务端负载就会下降(高并发场景)。类似于数据校验这种,前后端都需要做!

    10、前端需要有机制应对后端请求超时以及后端服务宕机的情况,友好的展示给用户。

    九、扩展阅读

    1、其实对于js,css,图片这类的静态资源可以考虑放到类似于阿里云的oss这类文件服务器上(如果是普通的服务器&操作系统,存储在到达pb级的文件后,或者单个文件夹内的文件数量达到3-5万,io会有很严重的性能问题),再在oss上配cdn(全国子节点加速),这样你页面打开的速度像飞一样, 无论你在全国的哪个地方,并且你的nginx的负载会进一步降低。

    2、如果你要玩轻量级微服务架构,要使用nodejs做网关,用nodejs的好处还有利于seo优化,因为nginx只是向浏览器返回页面静态资源,而国内的搜索引擎爬虫只会抓取静态数据,不会解析页面中的js,这使得应用得不到良好的搜索引擎支持。同时因为nginx不会进行页面的组装渲染,需要把静态页面返回到浏览器,然后完成渲染工作,这加重了浏览器的渲染负担。浏览器发起的请求经过nginx进行分发,URL请求统一分发到nodejs,在nodejs中进行页面组装渲染;API请求则直接发送到后端服务器,完成响应。

    3、如果遇到跨域问题,spring4的CORS可以完美解决,但一般使用nginx反向代理都不会有跨域问题,除非你把前端服务和后端服务分成两个域名。JSONP的方式也被淘汰掉了。

    4、如果想玩多端应用,注意要去掉tomcat原生的session机制,要使用token机制,使用缓存(因为是分布式系统),做单点,对于token机制的安全性问题,可以搜一下jwt。

    5、前端项目中可以加入mock测试(构造虚拟测试对象来模拟后端,可以独立开发和测试),后端需要有详细的测试用例,保证服务的可用性与稳定性。

    十、总结

    前后端分离并非仅仅只是一种开发模式,而是一种架构模式(前后端分离架构)。千万不要以为只有在撸代码的时候把前端和后端分开就是前后端分离了,需要区分前后端项目。前端项目与后端项目是两个项目,放在两个不同的服务器,需要独立部署,两个不同的工程,两个不同的代码库,不同的开发人员。

    前后端工程师需要约定交互接口,实现并行开发,开发结束后需要进行独立部署,前端通过ajax来调用http请求调用后端的restful api。前端只需要关注页面的样式与动态数据的解析&渲染,而后端专注于具体业务逻辑。

    4、如果想玩多端应用,注意要去掉tomcat原生的session机制,要使用token机制,使用缓存(因为是分布式系统),做单点,对于token机制的安全性问题,可以搜一下jwt。

    展开全文
  • JSP页面需要转换成servlet,servlet在编译,载入服务器内存中,初始化并执行,每一步在什么时候发生呢? –JSP页面仅在修改第一次被访问时,才会被转换成servlet并进行编译 –载入到内存中、初始化和执行遵循...

    JSP技术

    JSP页面需要转换成servlet,servlet在编译后,载入服务器内存中,初始化并执行,每一步在什么时候发生呢?
    –JSP页面仅在修改后第一次被访问时,才会被转换成servlet并进行编译
    –载入到内存中、初始化和执行遵循servlet的一般规则

    模板文件的创建

    JSP文档大部分由静态文本(一般是HTML)构成,称之为模板文本,为处理页面而创建的servlet只是将它们原封不动地传递给客户程序,但有两个例外:
    –如果输出中含有<%或%>,需要在模板中使用<\%或%\>
    –如果希望添加一段注释,使之出现在JSP页面但不出现在结果文档中,需要使用

    <%-- JSP Comment --%>

    下面这种形式的HTML注释按照常规的方式传递给客户程序

    <!--HTML Comment -->

    JSP脚本元素的类型

    使用JSP脚本元素可以将Java代码插入到与JSP页面相对应的servlet中
    (1)形如<%= Java Expression%>的表达式,它们在求值后插入到servlet的输出之中
    (2)形如<%Java Code%>的scriptlet,它们将插入到servlet的_jspService方法(由service方法调用)中
    (3)形如<%! Field/Method Declaration %>的声明,它们将插入到servlet类的定义中,不属于任何已有的方法

    JSP表达式的应用

    JSP表达式用来将值直接插入到输出中,它的形式如下:

    <%= Java Expression %>

    该表达式在求值,转换成字符串后,插入到页面中,求值是在运行期间执行

    JSP scriptlet

    JSP scriptlet可以将任意代码插入到servlet的_jspService方法中(由service方法调用),形式如下

    <% Java Code %>

    JSP表达式包含Java的值,不以分号结尾,而大多数JSP scriptlet包含Java语句,必须以分号结尾,如:

    <%=bar() %>
    <%bar();%>

    以上JSP片段在转换为servlet时,转换成以下内容:

    out.println(bar());
    bar();

    JSP声明

    使用JSP声明可以将方法或字段的定义插入到servlet类的主定义体中(位于对请求进行处理的_jspService方法之外),声明的形式如下:

    <%! Field or Method Definition %>

    要注意的是不要使用JSP声明覆盖servlet的标准生命周期方法(service、doGet、init等)由JSP页面转换而成的servlet已经使用了这些方法。

    预定义变量

    _jspService自动定义了9个局部变量,有时也称为是“隐含对象”,他们是局部变量的名称,注意是局部变量,不是常量,也不是JSP保留字,但是如果编写的代码不属于_jspService方法,那么就不能使用这些变量。因此,JSP表达式和JSP script可以使用这些变量,但是由于JSP声明产生_jspService方法之外的代码,所以声明中不能访问这些变量。
    (1)request
    这个变量是与请求相关联的HttpServletRequest
    (2)response
    这个变量是与发往客户的响应相关联的HttpServletResponse,因为输出流(out)一般都会缓冲,所以在JSP页面的主体内设置HTTP状态代码和响应报头一般都是合法的,如果将缓冲关闭,那么就必须在提供任何输出之前设置状态代码和报头。
    (3)out
    这个变量是用来输出发送到客户程序的Writer,可以使用page指令的buffer属性调整缓冲区的大小。
    (4)session
    这个变量是与请求相关联的HttpSession对象,如果使用page指令的session属性禁用自动会话跟踪,则不存在这个变量,并且,这种情况下对session变量的引用在JSP页面转换成servlet时会引起错误。
    (5)application
    这个变量和getServletContext返回的类型相同,都为ServletContext,servlet和JSP页面可以在ServletContext对象中存储持续性数据。
    (6)config
    这个变量是该页的ServletConfig对象。
    (7)pageContext
    JSP引入一个PageContext对象,通过它可以访问页面许多属性,比如getRequest、getResponse、getOut等。
    (8)page
    表示当前页面,类似于this。
    (9)exception
    仅在错误页面中使用。

    JSP page指令

    JSP指令影响由JSP页面生成的servlet整体结构,JSP指令的两种形式:

    <% directive attribute="value" %>
    <% directive attribute1="value1",attribute2="value2",…attributeN="valueN"%>

    属性值两边的双引号可以替换成单引号,但引号标记不能完全省略,如果要在属性值中使用引号,则要在它们之前添加反斜杠,’使用\’,”使用\”
    JSP page指令控制生成的servlet的结构,包含了以下一些大小写敏感的属性:import,contentType,pageEncoding,session,isELIgnored,buffer,autoFlush,info,errorPage,isErrorPage,isThreadSafe,language和extends

    import属性

    page指令的import属性指定JSP页面转换成servlet应该引入的包,默认情况下servlet会引入java.lang.*,javax.servlet.*,javax.servlet.jsp.*,javax.servlet.http.*,也许还包括一些服务器特有的包(不建议使用),import属性是page属性中唯一允许在同一文档中多次出现的属性。

    <%@page import="package.class"%>
    <%@page import="package1.class1,…packageN.classN"%>

    contentType和pageEncoding属性

    contentType属性设置Content-Type响应报头,标明即将发送到客户端的文档的MIME类型和字符集

    <%@page contentType="MIME-Type"%>
    <%@page contentType="MIME-Type;charset=Character-Set"%>

    常规的servlet默认MIME类行为text/plain,JSP页面默认的MIME类行为text/html
    如果只是想更改发送到客户端文档的字符集,可以使用pageEncoding属性

    <%@page pageEncoding="Page-Encoding"%>

    因为指令属性的值不是运行时计算的,所以不能将page指令像模板文本一样条件性地插入到输出中,如下例:

    <%if(test()) {%>
    <%@page contentType="application/vnd.ms-excel%>
    <%}%>

    这一示例中不管test()判断true还是false,页面都会生成excel内容

    session属性

    session属性控制页面是否参与HTTP会话

    <%@page session="true"%>默认
    <%@page session="false"%>

    true值表示,如果存在已有会话,则预定义变量session应该绑定到现有会话,否则,则创建新的会话并将其绑定到session。false表示不自动创建会话,在JSP页面转换成servlet时,对变量session的访问会导致错误。
    需要注意的是,false并不禁用会话跟踪——它只是阻止JSP页面对那些尚不拥有会话的用户创建新的会话,关闭某个页面的会话跟踪没有任何益处,除非有可能在同一客户会话中访问到的相关页面都关闭会话跟踪。

    buffer和autoFlush属性

    buffer属性指定out变量使用的缓冲区大小

    <%@page buffer="sizekb"%>
    <%@page buffer="none"%>

    如果要将缓冲区功能关闭,应该十分小心,这样做要求设置报头或状态代码的JSP元素都要出现在文件的顶部,位于任何HTML内容之前。
    autoFlush属性控制当前缓冲区充满之后,使应该自动清空输出缓冲区(默认),还是在缓冲区溢出后抛出一个异常

    <%@page autoFlush="true"%>
    <%@page autoFlush="false"%>

    buffer=”none”时,设置autoFlush=”false”是不合法的,因为没有缓冲区,也就不存在缓冲区溢出的情况

    errorPage和isErrorPage属性

    errorPage属性用来指定一个JSP页面,由该页面处理当前页面中抛出但未被捕获的任何异常

    <%@page errorPage="Error Page URL"%>

    指定的错误页面可以通过exception变量访问抛出的异常
    isErrorPage属性表示当前页是否可以作为其他JSP页面的错误页面

    <%@page isErrorPage="true"%>
    <%@page isErrorPage="false"%>默认

    在JSP页面中包含文件

    jsp:include动作:jsp:include动作允许我们在请求期间将其他页面的输出包含进来,它的主要优点是:在被包含的页面发生更改时,无需对主页面做出修改。它的主要缺点是:它所包含的是次级页面的输出,而非次级页面的实际代码。
    include指令:include指令可以在主页面转换成servlet之前,将JSP代码插入其中,它的主要优点是功能强大,所包含的代码可以含有总体上影响主页面的JSP构造,比如字段的定义和内容类型的设定。它的主要缺点是难以维护,只要被包含的页面发生改变,就得更新主页面。

    jsp:include动作

    jsp:include可以将下列内容插入到JSP的输出中:HTML页面内容,纯文本文档的内容,JSP页面的输出,servlet的输出。
    jsp:include动作在主页面被请求时,将次级页面的输出包含进来,尽管被包含的页面输出中不能含有JSP,但这些页面可以是其它资源(servlet或JSP创建输出)所产生的结果。服务器可以按照正常方式对被包含资源的URL进行解释,因此,这个URL可以是servlet或者JSP页面。

    page属性:指定所包含的页面

    我们使用page属性指定被包含的页面

    <jsp:include page="relative-path-to-resource" />

    这个属性是必不可少的,它应该是指向某种资源的相对URL,如果相对URL不以斜杠/开头,则将其解释为相对于主页面的位置;以斜杠/开头的相对URL被解释为相对于Web应用的根目录(注意:不是相对于服务器的根目录)。
    以斜杠/开头的URL可以记住次规则:任何时候,如果是由服务器处理它们,都按相对于当前Web应用进行解释;只有客户(浏览器)处理它们时,才会按相对于服务器的根目录来解释。
    注意不要将完整的HTML文档作为被包含页面,被包含页面种只能含有适合于出现在文件插入点出的HTML标签。

    flush属性

    这个属性是可选的,它指定将页面包含进来之前是否应该清空主页面的输出流(默认为false)

    jsp:param元素:增加请求参数

    被包含页面与最初请求的页面使用相同的请求对象,因此,被包含页面看到的请求参数一般与主页面相同,如果希望增加或替换这些参数,可以使用jsp:param元素(它有两项属性,name和value)

    <jsp:include page="/test/test.jsp">
        <jsp:param name="param" value="test"/>
    </jsp:include>

    如果jsp:param元素指定了主页面接收到的请求参数,那么由jsp:param指定的值仅在被包含文件中优先采用。

    include指令

    include指令可以在主JSP文档转换成servlet时(一般在它首次被访问时),将文件包含到文档中。

    <%@include file="Relative URL" %>

    服务器将被包含文件的内容逐字节插入到主页面中,然后将页面作为单个JSP页面进行处理

    jsp:include动作 include指令
    包含动作的发生时间 请求期间 页面转换期间
    包含的内容 页面的输出 文件的实际内容
    产生多少servlet 两个(主页面和被包含页面都会成为独立的servlet) 一个(被包含文件首先被插入到主页面中,然后得到页面被转换成servlet)
    被包含页面中可否设置影响主页面的响应报头 不可以 可以
    被包含页面中可否定义主页面使用的字段或方法 不可以 可以
    被包含页面更改时是否需要更新主页面 不需要 需要
    等同的servlet代码 RequestDispatcher的include方法

    使用include指令,如果包含的文件发生改变,那么用到它的所有JSP页面可能都需要更新,服务器需要能够检测出JSP页面发生改变这种情况,并在处理接下来的请求之前,将它转换成新的servlet,实际上几乎没有服务器支持类似的机制,因此,大多数服务器中,包含文件发生更改时,对于所使用到的该文件的JSP文件,我们都得更新它的修改日期。
    对于文件包含,应该尽可能地使用jsp:include,仅在所包含的文件中定义了主页面要用到的字段或方法,或者所包含的文件设置了主页面的响应报头时,才应该使用include指令。

    JavaBean组件在JSP中的应用

    bean的应用:基本任务

    1、jsp:useBean
    这个元素的最简单形式只是构建一个新的bean,用以载入将要用在JSP页面中的bean,如果提供scope属性,则既可以构建新的bean,也可以访问现存的bean。

    <jsp:useBean id="beanName" class="package.Class"/>

    这条语句类似于:实例化由class指定的类,变量的名字由id指定,其中class属性必须使用完全限定类名。
    如果这个bean业已存在,并且只想使用现有的对象,而非创建新的对象,则可以只使用type属性,省略class属性。

    <jsp:useBean id="beanName" type="package.Class"/>

    2、jsp:getProperty
    这个元素读取或输出bean属性的值,用该元素读取属性是getXx调用的简单记法。

    <jsp:getProperty name="beanName" property="propertyName"/>

    其中name属性应该与jsp:useBean给定的id匹配,它的property属性指定需要的属性。除了可以使用jsp:getProperty以外,还可以使用JSP表达式,显式地调用对象的方法,变量的名称由id指定。

    <jsp:getProperty name="book1" property="title"/>
    <%=book1.getTitile() %>

    3、jsp:setProperty
    这个元素修改bean的属性(即调用形如setXxx的方法)。

    <jsp:setProperty name="beanName" property="propertyName" value="propertyValue" />

    其中name属性与jsp:useBean的id匹配,property为要更改的属性名称,value为新的值。jsp:setProperty动作的一种替代方式是使用scriptlet显式地调用bean对象的方法。

    <jsp:setProperty name="book1" property="titile" value="TestBook"/>
    <% book1.setTitle("TestBook"); %>

    值得注意的是,value属性允许给出的值为请求期间的表达式,如下例value值可以从请求的参数中获取。

    <jsp:setProperty name="entry" property="itemID" value='<%=request.getParameter("itemID") %>' />

    使用这种方法从请求参数中获取到的值默认为String类型的,如果bean中属性的类型为非String,如Integer、Double的,那么需要显式地将String类型转换为其他的基本类型,代码稍显繁琐。JSP提供一种方案,它可以将属性与请求参数相关联,自动执行从字符串到数字、字符和布尔值的类型转换,我们可以不使用value属性,而是使用param属性指定一个输入参数,被指定的请求参数的值自动用作bean属性的值,由String到基本类型的转换都自动执行。

    <jsp:setProperty name="entry" property="numItems" param="numItems"/>

    如果请求参数的名称和bean属性的名称相同,还可以进一步简化这段代码。

    <jsp:setProperty name="entry" property="numItems"/>

    但是建议最好明确地列出参数。
    我们可以使用”*”作为property参数的值将bean所有的属性与同名的请求参数关联起来。系统从请求参数开始查找匹配的bean属性,而非采用相反的方式。

    <jsp:setProperty name="entry" property="*"/>

    共享bean

    jsp:useBean创建的对象不仅是在_jspService方法中定义的一个局部变量,它还可以存储在4个不同的位置,根据jsp:useBean的可选属性scope的值来确定。scope可选的值有:page(默认),request,session和application。
    1、page
    page是默认值,当省略scope属性时也会得到相同的行为。page作用域表示:在处理当前请求期间,除了要将bean对象绑定到局部变量外,还应该将它放在PageContext对象中。由于每个页面和每个请求都有不同的PageContext对象,所以scope=”page”(或省略scope)表示不共享bean,也就是针对每个请求都创建新的bean。
    2、request
    这个值表示:当处理当前请求期间,除了要将bean对象绑定到局部变量外,还应该将它放在HttpServletRequest对象中,从而可以通过getAttribute方法访问它。
    3、session
    这个值表示:除了要将bean绑定到局部变量以外,还要将它存储到当前请求关联的HttpSession对象中,可以通过getAttribute获取存储在HttpSession中的对象。
    4、application
    这个值表示:除了要将bean绑定到局部变量以外,还要将它存储在ServletContext中,ServletContext由Web应用中多个servlet和JSP页面共享。

    根据条件创建bean

    两种情形下,我们可以有条件地对与bean相关的元素进行求值:
    1、仅当找不到相同的id和scope的bean时,jsp:useBean元素才会实例化新的bean,如果存在相同的id和scope的bean,则只是将已有的bean绑定到相关的变量。
    2、我们使用

    <jsp:useBean …>statements</jsp:useBean>

    jsp:useBean的起始标签和结束标签之间的语句只在创建新的bean时才执行,如果使用已有的bean,则不执行。

    请求转发与请求重定向

    转发请求使用RequestDispatcher的forward方法。RequestDispatcher的获取需要调用ServletRequest的getRequestDispatcher方法并提供相对地址。
    请求重定向使用HttpServletRequest的sendRedirect方法。

    请求转发行为汇总

    1、控制的转移完全在服务器上进行,不涉及任何网络数据流。
    2、用户不会看到目的JSP页面的地址,而且我们还可以将页面放在WEB-INF中,防止用户不经过建立数据的servlet,直接访问这些页面。如果JSP页面只在由servlet生成的数据的上下文中才有意义,则更应该这样做。

    请求重定向行为汇总

    1、控制转移通过向客户发送302状态代码和Location响应报头来完成,转移需要另外的网络往返。
    2、用户能够看到目的页面的地址,并可以记下来,独立地访问。如果将JSP设计为数据缺失时使用默认值,这种方式比较适用。

    请求转发与请求重定向的区别

    1、请求重定向需要客户连接到新的资源,而请求转发完全在服务器上进行处理
    2、请求重定向不自动保留所有的请求数据,而请求转发保留
    3、请求重定向产生不同的最终URL,而请求转发维护最初servlet的URL
    第3点表示,如果目的页面使用图像和样式表的相对URL,那么这些URL应该相对于servlet的URL,或服务器的根目录,不能相对目的页面的实际位置,最简单的解决方案是给出样式表文件在服务器上的完整路径。

    表达式语言

    表达式语言的调用

    EL元素可以出现在常规文本和JSP属性标签中,只要JSP标签的属性允许常规JSP表达式。

    Name:${expression1}
    <jsp:include page="${expression2}"/>

    在标签属性中使用表达式语言时,我们可以使用多个表达式。

    <jsp:include page="${exp1}and${exp2}"/>

    如果希望${出现在页面输出中,在JSP页面中需要使用\${,如果希望在EL表达式中使用单引号和双引号,则需分别使用\’和\”。

    访问作用域变量

    PageContext、HttpServletRequest、HttpSession和ServletContext称为作用域变量,要输出作用域变量的值,只需在表达式语言元素中使用它的名字,如:

    ${name}

    表示在PageContext、HttpServletRequest、HttpSession和ServletContext(依照此处列出的次序)中查找名为name的属性,如果找到该属性,则调用它的toString方法返回结果,如果没有找到任何东西,则返回空字符串(不是null或错误消息),下面两个表达式是等同的:

    ${name}
    <%=pageContext.findAttribute("name")%>

    如果多个作用域中都存储了同名的属性,则表达式会按照预先定义好的次序搜索每个作用域并找到第一个属性的值。

    访问bean的属性

    JSP表达式语言为访问bean的属性提供了一种点号记法,如果要返回某个作用域变量customer的firstName属性,只需使用${customer.firstName}
    我们也可以使用数组记法替代点号记法,如:

    ${name.property}

    替换为:

    ${name["property"]}

    数组记法有两项优势:
    1、它允许我们在请求期间计算属性的名称,使用数组记法时,方括号内的值本身就可以是一个变量,而使用点号记法时,属性名必须是字面值。
    2、数组记法允许我们使用那些不能成为合法属性名的值,在访问bean属性时,这没有任何用处,但在访问集合或请求报头时,它很有用。

    访问集合

    当作用域变量attributeName指向数组、List或Map时,我们可以使用下面的方式访问集合中的项:

    ${attributeName[entryName]}

    1、如果作用域变量为数组,则entryName为索引,如下面的表达式会输出数组的第一项:

    ${cunstomerNames[0]}

    2、如果作用域变量为实现了List接口的对象,则entryName为索引,如下面的表达式会输出List的第一项

    ${cunstomerNames[0]}

    3、如果作用域变量实现了Map接口的对象,则entryName为键,如下面表达式会从Map中获取key为maryland的值:

    ${stateCapitals["maryland"]}

    如果Map的键满足Java变量名的相关规定(如不能有小数点、空格和短划线等字符)则可以用点号记法来取代数组记法:

    ${stateCapitals.maryland}

    引用隐式对象

    表达式语言可以在任何JSP页面中使用,为了使得表达式语言的使用更有效率,相应的规范定义了下面的隐式对象。
    1、pageContext
    pageContext对象引用当前页面的PageContext,PageContext类依次拥有request,response,session,out和servletContext属性,如下面语句可以输出当前的会话ID:

    ${pageContext.session.id}

    2、param和paramValues
    这些对象允许我们访问基本的请求参数的值(param)或请求参数值的数组(paramValues),如果当前请求中不存在这个参数,则返回空字符串,而非null。
    3、header和headerValues
    这些对象分别访问HTTP请求报头的主要值以及全部值。
    4、cookie
    cookie对象允许我们快捷地引用输入cookie,但是它的返回值是Cookie对象,不是cookie的值,如果要访问cookie的值,则需要使用Cookie类标准的value属性。
    5、initParam
    initParam对象允许我们容易地访问上下文初始化参数。
    6、pageScope,requestScope,sessionScope,applicationScope
    这些对象允许我们限定系统应该在什么地方查找作用域变量,例如在遇到下面的表达式${name}时,系统会依次在PageContext,HttpServletRequest,HttpSession和ServletContext中查找名为name的作用域变量,返回所找到的第一个匹配项。如果遇到下面的表达式${requestScope.name},则系统只在HttpServletRequest中查找。

    表达式语言中运算符的应用

    算术运算符

    1、+和-
    这二者是常规的加法和减法运算符,但是有两点例外,首先,如果任一操作数为字符串,那么在运行时,字符串会被自动解析成数值(但是系统并不自动捕获NumberFormatException)。其次,如果任一操作数为BigInteger或BigDecimal类型,系统会使用相应的add和subtract方法。
    2、*,/和div
    它们是常规的乘法和除法运算符,但有几点例外,第一点如同+和-运算符一样,类型转换自动完成,第二,常规的算术运算符优先级依旧使用。
    3、%和mod
    %或与之等同的mod运算符计算模数。

    关系运算符

    1、==和eq
    这两个相等性运算符检查参数是否相等,但是相比于Java的==运算符,他们更像Java的equals方法,如果这两个操作数为同一对象,则返回true。
    2、!=和ne
    这两个相等性运算符检查参数是否不同,同样相比于Java的!=运算符,它们更像Java的equalse方法的否定式。
    3、<和lt,>和gt,<=和le,>=和ge
    它们都是标准的算术运算符,但是有两点例外,首先,类型转换的执行同==和!=,其次,如果参数为字符串,则进行字面比较。

    逻辑运算符

    &&,and,||,or,!和not
    它们是标准的逻辑AND,OR和NOT运算符,它们将参数强制转换成Boolean,并使用常规的Java短路求值。

    空运算符

    empty
    如果这个运算符的参数为null,空字符串,空数组,空Map或空集合,则返回true,否则返回false。

    展开全文
  • 希望每次遇到“abc”,则替换“abc”以及其到行尾的内容“abc efg” 即上面的文本最终替换: abc efg 123 abc efg 解决: ① 在替换对话框,查找内容里输入“abc.*” ② 同时勾选“正则表达式”复选框,然后...
  • JSp+ajax用户登录验证

    2013-08-14 20:09:21
    //转换再传输 xmlHttp.open("GET",url,true);//加时间戳防止IE缓存 //xmlhttp.setRequestHeader( "Content-Type", "text/html;charset=UTF-8" ); xmlHttp.onreadystatechange = handleStateChange1; ...
  • 思考项目做部分

    2019-03-19 14:04:38
    二、为什么主要用html不是用jsp 帖子地址:https://bbs.csdn.net/topics/390939813 论坛答案:为了前后端分离,并且提高效率。 个人认为重点:jsp限定了是java语言且绑定太死,并且转换为servlet太浪费时间,效率...

    一、设计

    主要需求,可能会遇见的BUG,重灾区

    二、为什么主要用html不是用jsp

    帖子地址:https://bbs.csdn.net/topics/390939813

    论坛答案:为了前后端分离,并且提高效率。

    个人认为重点:jsp限定了是java语言且绑定太死,并且转换为servlet太浪费时间,效率相对较低。并且在大型项目中可能存在多语言,对于开发维护很局限。

    疑问:开rest是什么意思?

        寻找到的答案列表:REST原则。链接:https://blog.csdn.net/mmd1234520/article/details/69943070

        

     

    展开全文
  • //将字符串转换成整型 intPage = java.lang.Integer.parseInt(strPage); if(intPage) intPage = 1; } //out.println(intPage); %> <html> <base href="<%=basePath%>"> 视频课堂 ...
  • java面试宝典

    2013-02-28 16:04:01
    144、当我重编译我的JSP使用的一个类为什么JVM继续使用我的老CLASS? 36 145、<%@include file="abc.jsp"%>与<jsp:include page="abc.jsp"/>之间的差别? 36 146、JSP的缺点? 36 148、如何实现JSP的国际化? 36...
  • 千方百计笔试题大全

    2011-11-30 21:58:33
    144、当我重编译我的JSP使用的一个类为什么JVM继续使用我的老CLASS? 36 145、 file="abc.jsp"%>与<jsp:include page="abc.jsp"/>之间的差别? 36 146、JSP的缺点? 36 148、如何实现JSP的国际化? 36 150、...
  • 最新Java面试宝典pdf版

    热门讨论 2011-08-31 11:29:22
    12.金额转换,阿拉伯数字的金额转换成中国传统的形式如:(¥1011)->(一千零一拾一元整)输出。 81 三. html&JavaScript&ajax部分 82 1. 判断第二个日期比第一个日期大 82 2. 用table显示n条记录,每3行换一次...
  • Java面试宝典2010版

    2011-06-27 09:48:27
    12.金额转换,阿拉伯数字的金额转换成中国传统的形式如:(¥1011)->(一千零一拾一元整)输出。 三. html&JavaScript&ajax部分 1. 判断第二个日期比第一个日期大 2. 用table显示n条记录,每3行换一次颜色,即...
  • 12.金额转换,阿拉伯数字的金额转换成中国传统的形式如:(¥1011)->(一千零一拾一元整)输出。 81 三. html&JavaScript&ajax部分 82 1. 判断第二个日期比第一个日期大 82 2. 用table显示n条记录,每3行换一次...
  • JAVA面试题最全集

    2010-03-13 13:09:10
    编码转换,怎样实现将GB2312编码的字符串转换为ISO-8859-1编码的字符串。 9.Java中访问数据库的步骤,Statement和PreparedStatement之间的区别。 10.找出下列代码可能存在的错误,并说明原因: 二、JSP&Servlet...
  • 为什么要有GC?  GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域...
  • java 面试题 总结

    2009-09-16 08:45:34
    为什么要有GC?  GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域...
  • 设定字符串“张三,你好,我是李四” 产生张三的密钥对(keyPairZhang) 张三生成公钥(publicKeyZhang)并发送给李四,这里发送的是公钥的数组字节 通过网络或磁盘等方式,把公钥编码传送给李四,李四接收到张三编码...
  • JAVA上百实例源码以及开源项目

    千次下载 热门讨论 2016-01-03 17:37:40
    有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码加以改进做小工具。 Java右键弹出...
  • 我当然不清楚ASP/JSP能做些什么。不过明确的是编写那样的代码有多简单,购买它们会有多昂贵以及它们需要多么昂贵和强大的硬件。如果你有什么中立的观点(比如说没有被SUN和Microsoft的百万美金所影响),请顺便通知...
  • java开源包1

    千次下载 热门讨论 2013-06-28 09:14:34
    J2C 将 Java 代码转 C++ 代码,这是源码级别的转换,输出的 C++ 代码是有效的代码。 OSGi 分布式通讯组件 R-OSGi R-OSGi 是一套适用于任意满足 OSGi 架构的分布式通讯组件。它以 jar 的形式发布,部署容易,使用...
  • java开源包12

    热门讨论 2013-06-28 10:14:45
    J2C 将 Java 代码转 C++ 代码,这是源码级别的转换,输出的 C++ 代码是有效的代码。 OSGi 分布式通讯组件 R-OSGi R-OSGi 是一套适用于任意满足 OSGi 架构的分布式通讯组件。它以 jar 的形式发布,部署容易,使用...
  • Java资源包01

    2016-08-31 09:16:25
    J2C 将 Java 代码转 C++ 代码,这是源码级别的转换,输出的 C++ 代码是有效的代码。 OSGi 分布式通讯组件 R-OSGi R-OSGi 是一套适用于任意满足 OSGi 架构的分布式通讯组件。它以 jar 的形式发布,部署容易,使用...
  • java开源包101

    2016-07-13 10:11:08
    J2C 将 Java 代码转 C++ 代码,这是源码级别的转换,输出的 C++ 代码是有效的代码。 OSGi 分布式通讯组件 R-OSGi R-OSGi 是一套适用于任意满足 OSGi 架构的分布式通讯组件。它以 jar 的形式发布,部署容易,使用...
  • java开源包11

    热门讨论 2013-06-28 10:10:38
    J2C 将 Java 代码转 C++ 代码,这是源码级别的转换,输出的 C++ 代码是有效的代码。 OSGi 分布式通讯组件 R-OSGi R-OSGi 是一套适用于任意满足 OSGi 架构的分布式通讯组件。它以 jar 的形式发布,部署容易,使用...
  • java开源包6

    热门讨论 2013-06-28 09:48:32
    J2C 将 Java 代码转 C++ 代码,这是源码级别的转换,输出的 C++ 代码是有效的代码。 OSGi 分布式通讯组件 R-OSGi R-OSGi 是一套适用于任意满足 OSGi 架构的分布式通讯组件。它以 jar 的形式发布,部署容易,使用...
  • java开源包10

    热门讨论 2013-06-28 10:06:40
    J2C 将 Java 代码转 C++ 代码,这是源码级别的转换,输出的 C++ 代码是有效的代码。 OSGi 分布式通讯组件 R-OSGi R-OSGi 是一套适用于任意满足 OSGi 架构的分布式通讯组件。它以 jar 的形式发布,部署容易,使用...
  • java开源包8

    热门讨论 2013-06-28 09:55:26
    J2C 将 Java 代码转 C++ 代码,这是源码级别的转换,输出的 C++ 代码是有效的代码。 OSGi 分布式通讯组件 R-OSGi R-OSGi 是一套适用于任意满足 OSGi 架构的分布式通讯组件。它以 jar 的形式发布,部署容易,使用...
  • java开源包9

    热门讨论 2013-06-28 09:58:55
    J2C 将 Java 代码转 C++ 代码,这是源码级别的转换,输出的 C++ 代码是有效的代码。 OSGi 分布式通讯组件 R-OSGi R-OSGi 是一套适用于任意满足 OSGi 架构的分布式通讯组件。它以 jar 的形式发布,部署容易,使用...
  • java开源包7

    热门讨论 2013-06-28 09:52:16
    J2C 将 Java 代码转 C++ 代码,这是源码级别的转换,输出的 C++ 代码是有效的代码。 OSGi 分布式通讯组件 R-OSGi R-OSGi 是一套适用于任意满足 OSGi 架构的分布式通讯组件。它以 jar 的形式发布,部署容易,使用...
  • 然后通过 Web Server 将模板解析一个个 HTML 文件,浏览器只负责渲染这些 HTML 文件。这个阶段还没有前后端的分工,通常是后端工程师顺便写了前端页面。 <p><a name="34b9b83b"></a></p> 基于 AJAX 的...
  • D) 程序将字符型转换为unicode编码并和b的数值相加的和输出。 题目3: 下面的说法中,错误的是:d(选择1项) A) 在Java中标志符可以是字母、下划线、数字或$符号。 B) 在Java中布尔类型不能和数字之间不能来回...

空空如也

空空如也

1 2
收藏数 37
精华内容 14
关键字:

为什么html转换成jsp后