JSP的本质

JSP本质上就是Servlet, 正常情况下, 它会在第一次被访问的时候被容器转化成Java代码, 然后再从Java代码编译成.class文件, 之后实际就和Servlet没区别了, 也就是多个请求也只有这一个实例, 最终仍然是通过多线程单实例的方式来完成任务. 所以其实就算你写的JSP代码有问题, 也只有在用户访问它的时候才能看到, 项目部署的时候是看不到的. 当然某些容器提供部署的同时完成代码编译加载的功能, 默认是不开启的.

JSP中几种常见的元素

JSP其实就是html中带了一些其他的元素以实现表现层(viewer)的功能, 下面是一些常见JSP元素 :

1. Scriptlet : <%    %> : 里面可以写Java代码, 这里的Java代码在最后会被统一移到生产的类Servlet类的类似serveice的方法里面 :
<% System.out.println(123); %> 2. 表达式 : <%= %> : 里面的内容将作为out.println()的参数, 被打印在页面上 :
<%=
config.getInitParameter("name")
%>
3. 声明 : <%! %> : 里面可以声明类的属性和方法, 用来弥补scriptlet中声明变量的均为局部变量的缺陷
<%!
private static int x = 3; private void print(){
System.out.println(123);
}
%> 4. 指令 : <%@ %> : 向容器提供一些特殊的指示 :
这里例子是page指令的import 和 contentType属性, 还有其他属性, 同时其实指令还有include和taglib, 之后有机会再提.
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="java.util.LinkedList" %> : 导入你需要在这个Jsp/Servlet 里面使用的包

JSP中的Servlet

上面说到JSP本质上就是Servlet, 那么也就是Servlet里面的一些东西它也有 :

隐式对象

在Scriptlet内部的一些常用的隐式对象(这里要注意的是只能在Scriptlet内部也就是那个类service方法的内部使用, 因为这些变量实际上都是在其内部定义的) :

  1. out : Servlet中需要通过resp.getWriter()来获得.
  2. request, response : Servlet中作为doGet/doPost/... 等方法的参数传入.
  3. session : 即Servlet中的HttpSession, 在Servlet通过req.getSession()来获得.
  4. application : Servlet中通过getServletContext()来获得
  5. config : Servlet中通过getServletConfig()来获得. (没错, JSP也可以设置初始化参数, 具体设置方法在后面提到)
  6. pageContext : 里面包含了其他隐式对象的引用

可以覆盖的方法

下面是可以覆盖的几个方法, 其作用和Servlet相同就不多说了 :

<%!
@Override
public void jspInit(){ } @Override
public void jspDestroy(){ } %>

JSP初始化参数的设置

然后来看看JSP如何设置初始化参数 :

    <servlet>
<servlet-name>indexJsp</servlet-name>
<jsp-file>/test.jsp</jsp-file> <init-param>
<param-name>name</param-name>
<param-value>index.jsp</param-value>
</init-param>
</servlet> <servlet-mapping>
<servlet-name>indexJsp</servlet-name>
<!--<url-pattern>/xixi</url-pattern>-->
<url-pattern>/test.jsp</url-pattern>
</servlet-mapping>

可以看到其实和Servlet大同小异, 要注意的是, 这里如果mapping中url-pattern不用jsp的实际路径而是使用虚拟路径的话, 会出现一个问题, 如果用户知道真实的jsp的路径, 他仍然可以访问, 但是那个jsp并不会获得初始化参数. 必须要使用url-pattern对应的路径才能获得初始化参数. 由于行为逻辑基本与Servlet相同, 所以在执行jspInit的时候已经可以使用getServletConfig()来获得初始化参数了.

属性的设置以及获取 :

类似于Servlet, 我们可以通过以下隐式对象来设置属性 :

  1. application 对应 ServletContext
  2. session 对应 HttpSession
  3. request 对应 HttpServletRequest
  4. 这里多了一个pageContext 也可以用来设置属性, 它设置的属性只在该page内共享, 但它也能设置/查找上面三者的属性, 具体规则就不表了.

JSP的转折

令人遗憾的是, 上面所说的大部分JSP元素, 实际上都是不推荐使用的 : 例如Scriptlet, 表达式 和声明(这三者均属于脚本代码), 因为这些东西使得Web的前后端之间无法很好地分离, 甚至在web.xml中存在禁用这三种元素的标记 :

    <jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<scripting-invalid>true</scripting-invalid>
</jsp-property-group>
</jsp-config>

一旦设置这个标记之后, 服务器部署正常, 但是一旦访问使用了上述元素的JSP网页, 网页直接HTTP 500. 那我们该使用什么呢? 答案是标准动作 + EL(expression language) + JSTL标记...

标准动作

首先要对bean有个基本的认识, 如果没有认识百度一下吧, 这里我个人由于接触的比较多就不提了, 由于在Java中bean没有在语言层面上实现所以有点麻烦. 这里我使用的Student类的源代码 :

package beanPackage;

public class Student {
private int age;
private String name; public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
}
}

JSP中总共有三个bean标准动作 :

1.   <jsp:useBean id="s" class="beanPackage.Student" scope="application" /> 这里scope指的是查找的范围, 默认为page, 可以设置为application, session, request, page分别对应上面提到的jsp中的4中属性设置的方式, 而你属性设置中其实是一个键值对, 这里的键就对应该标签中的id, 由于设置的属性均为Object, 所以还需要有class来识别其class, 而且这里的class必须使用完全限制名, 在上面使用page指令的import属性导入模块是无效的. 要注意的是, 这里之所以要这三个属性, 实际上是因为最终JSP还是要转化为Java代码的. 这句话也就会转化为类似 : beanPackage.Student s = (beanPackage.Student)application.getAttribute("s")的话.
2. <jsp:getProperty name="s" property="name"/> 这里的s对应上面已经获取到的Student的id, property对应Student中的name属性. 这句话会在html中打印这个student的名字.
3. <jsp:setProperty name="s" property="age" value="21"/> 这里s对应上面获取到的Student的id, age对应Student中的age属性. 这句话会将这个Student实例的age改为21.

附加 :

关于useBean

实际上useBean总是会返回一个bean对象, 就用上面的例子来说<jsp:useBean id="s" class="beanPackage.Student" scope="application" />, 如果在application内没有这个Student, 那么它会利用bean的无参数构造函数自动构造一个然后添加到application当中. 基于这个特性, 实际上这个标签的还可以写为 :

  <jsp:useBean id="s" class="beanPackage.Student">
<jsp:setProperty name="s" property="name" value="Fred" />
<jsp:setProperty name="s" property="age" value="21" />
</jsp:useBean>

useBean内部的内容只有当没有在作用域内找到该对象时才会执行.

实际上jsp:useBean之中还可以设置type, 例如你想到生成的对象是Human s = new Student()的时候, 那么这句话可以写为

<jsp:useBean id="s" type="beanPackage.Human" class="beanPackage.Student" scope="application" />

另外如果只有type没有class, 此时如果能在作用域内找到对象, 那么这个对象的引用将是type中指定的类型, 如果不能找到, 直接报错.

关于setProperty

实际上setProperty中还可以设置param :

  <jsp:useBean id="k" class="beanPackage.Student">
<jsp:setProperty name="k" property="name" param="name" />
<jsp:setProperty name="k" property="age" param="age" />
</jsp:useBean>

这个param能直接从request的参数中寻找名字为name和age的参数并且赋值给我们此处的Student实例. 更牛逼的是, 如果你request参数的名字和你实际Property的名字相同的话, 就比如上述例子中, 则可以直接省略param :

  <jsp:useBean id="k" class="beanPackage.Student">
<jsp:setProperty name="k" property="name" />
<jsp:setProperty name="k" property="age" />
</jsp:useBean>

当然最牛逼的还是这个, 使用*, 这种情况下容器会自动迭代所有request中的参数来尝试匹配你的bean的property, 并设置为对应的值.

  <jsp:useBean id="k" class="beanPackage.Student">
<jsp:setProperty name="k" property="*" />
</jsp:useBean>

其实这里还有一点, 我的age的类型是int, 但是request传入的所有的参数值都为String, 但是仍然能够匹配, 这是因为容器提供了基本类型和String的自动转换. 另外如果我们实例的类有父类, 父类的属性也会得到匹配.

EL

EL在JSP 2.0 已经成为规范的一部分, 它有自己的语法, 属于另外一类JSP元素. 当然也有忽略EL的方法, 这里不表. 有了标准动作为什么需要EL呢? 就一个很简单的例子, 比如上面的Student有一个性质是Book, 我们想要显示这个Book的name :

<jsp:getProperty name="k" property="book"/>   --> 会打印 book.toString

这时候如果用el的话就是 :

${k.book.name}

el表达式实际上很简单 : 任何语句都包含在${}当中, 然后可以用.[]来取值, 用点时, 左边只能是map或者JSP四个作用域中的某个作用域的属性(某个bean), 而右边必须是map的键或者是bean的Property. []则使用空间更大, 左边可以放map, bean, list 和 数组. 这里你可以直接用index来获取list或者array中的某个值. 例如${list[1]} 或者 ${list["1"]}, 这两者是一样的, 最终都会转化为1, 然后寻找list中的第二个. 如果是在四个作用域内已经设置过的属性(某个bean), 实际上并不需要使用xxxScope.xxxBean.xxxProperty或者是xxxScope["xxxBean"].xxxProperty, 直接xxxBean.xxxProperty即可. 查找顺序是 page, request, session, context依次查找.

el中的隐式对象 :

  1. pageScope, requestScope, sessionScope, applicationScope这4个分别对应4个作用域下的保存属性的map
  2. param, paramValues 这是http请求参数的map, 后者用于存在多个同名参数情况.
  3. header, headValues 这是请求首部的map
  4. cookie 关于cookie的map, Servlet提供的是一个数组, 所以这里比Servlet要方便.
  5. initParam 这个不是Servlet的初始化参数而是context的初始化参数, 也就是整个应用的初始化参数的map.
  6. pageContext 这个不是map, 这个和上面scriptlet中那个一样. 可以用这个访问Servlet的初始化参数 : ${pageContext.servletConfig.getInitParameter("name")}

这里还有内容暂时不提, 还有el函数和jstl没有提, 先留个坑, 以后有时间再填...

JSP中的包含与转发

JSP中有两种包含方式 :

1. <%@ include  file="the_jspFile_path"%> : 这种方式的包含实际上发生在jsp被转换成java代码之前, 也就是说, 将被包含的jsp直接替换到该语句的位置, 然后将形成的新的的jsp转化为java代码, 然后编译加载并提供服务. 所以这种包含也称之为静态包含.

2. <jsp:include page="the_jspFile_path" /> : 这种方式的包含实际上不算包含, 当请求来临时, 主jsp文件和被包含jsp文件各自被转换编译加载后, 由主jsp文件形成的类运行时调用被包含jsp文件形成的类, 个人感觉可以理解为请求被包含的jsp文件形成的类在运行时帮助主jsp文件形成的类完成一部分页面的构造工作. 所以这种包含也称之为动态包含. 这种包含还可以有参数.

<jsp:include page="the_jspFile_path"><jsp:param name="param_name" value="param_value" />
</jsp:include> 对于被包含页面而言, 请求参数中增加了上述添加的这个.

处于效率考虑, 个人感觉没有特殊要求的话, 统一使用第一个比较好...

JSP标准动作中还存在一个用于转发的动作, 该动作和 :

<jsp:forward page="the_page_path" />
实际上该动作等同于
req.getRequestDispatcher("/WEB-INF/jsp/login/login.jsp").forward(req, resp);
是在服务器端进行的, 用户并不能看到url的变化. 同时该动作不需要担心写在jsp中部会导致转发之后之前加载的页面会打印出来, 因为发生这个动作时容器会清空缓冲区, 理论上只要没有使用flush()显式地将缓冲区内容打印到页面都行. **当然之前提到的jsp include动作中的增加参数语句在这里同样试用.**

关于JSP的更多相关文章

  1. myeclipse学习总结一(在MyEclipse中设置生成jsp页面时默认编码为utf-8编码)

    1.每次我们在MyEclispe中创建Jsp页面,生成的Jsp页面的默认编码是"ISO-8859-1".在这种情况下,当我们在页面中编写的内容存在中文的时候,就无法进行保存.如下图 ...

  2. jsp前端实现分页代码

    前端需要订一page类包装,其参数为 private Integer pageSize=10; //每页记录条数=10 private Integer totalCount; //总记录条数 priv ...

  3. jsp中出现onclick函数提示Cannot return from outside a function or method

    在使用Myeclipse10部署完项目后,原先不出错的项目,会有红色的叉叉,JSP页面会提示onclick函数错误 Cannot return from outside a function or m ...

  4. jsp页面无法识别el表达式的解决方案

    今天在写一个springmvc的小demo时,碰到一个问题,在jsp页面中书写为${user.username}的表达式语言,在浏览器页面中仍然显示为${user.username},说明jsp根本不 ...

  5. 浅谈JSP中include指令与include动作标识的区别

    JSP中主要包含三大指令,分别是page,include,taglib.本篇主要提及include指令. include指令使用格式:<%@ include file="文件的绝对路径 ...

  6. 浅谈JSP注释

    HTML注释 JSP文件是由HTML尿急和嵌入的Java程序片段组成的,所以在HTML中的注释同样可以在JSP文件中使用.注释格式:<!--注释内容--> <!-- 欢迎提示信息! ...

  7. JSP 标准标签库(JSTL)

    JSP 标准标签库(JSTL) JSP标准标签库(JSTL)是一个JSP标签集合,它封装了JSP应用的通用核心功能. JSTL支持通用的.结构化的任务,比如迭代,条件判断,XML文档操作,国际化标签, ...

  8. Nginx服务器之Nginx与tomcat结合访问jsp

    本文使用linux centos系统 本文概述: JSP是一种动态网页技术标准.使用的方式是在HTML文件中插入程序段和JSP标记,而形成JSP文件.使用JSP开发WEB应用可以跨平台开发.但jsp需 ...

  9. 基于jsp+servlet图书管理系统之后台万能模板

    前奏: 刚开始接触博客园写博客,就是写写平时学的基础知识,慢慢发现大神写的博客思路很清晰,知识很丰富,非常又价值,反思自己写的,顿时感觉非常low,有相当长一段时间没有分享自己的知识.于是静下心来钻研 ...

  10. JSP页面跳转的几种实现方法

    使用href超链接标记      客户端跳转 使用JavaScript               客户端跳转 提交表单                        客户端跳转 使用response ...

随机推荐

  1. 【Heritrix基础教程之3】Heritrix的基本架构 分类: H3_NUTCH 2014-06-01 16:56 1267人阅读 评论(0) 收藏

    Heritrix可分为四大模块: 1.控制器CrawlController 2.待处理的uri列表  Frontier 3.线程池 ToeThread 4.各个步骤的处理器 (1)Pre-fetch ...

  2. asm 的hello world 2011.04.28

    这几天一直在弄一个嵌入式的程序,搭环境,熟悉库函数,熟悉汇编,乱成一锅粥,到现在还是没有什么系统性的收获. 或许下周弄出来吧,(一定得弄出来,不然老大该跟我急了……). 今天,熟悉汇编,好歹用汇编写出 ...

  3. 【33.20%】【LA 4320】【Ping pong】

    [Description] N (3 ≤ N ≤ 20000) ping pong players live along a west-east street(consider the street ...

  4. [tmux] Manage terminal workspaces using session naming

    It's a lot easier to manage your tmux session when they have sensible names. We'll cover: How to cre ...

  5. html5-3 html5标签(热点地图如何实现)(边学边做)

    html5-3 html5标签(热点地图如何实现)(边学边做) 一.总结 一句话总结:热点地图用绝对定位实现. 1.自定义列表怎么弄? dl  自定义列表dt  自定义标题dd  自定义列表内容 2. ...

  6. javaScript DOM编程经常使用的方法与属性

    DOM是Document Object Model文档对象模型的缩写.依据W3C DOM规范,DOM是一种与浏览器,平台,语言无关的接口,使得你能够訪问页面其它的标准组件. Node接口的特性和方法 ...

  7. uboot中rtc顶层分析

    uboot一般不会要求开启rtc,只是还是支持rtc以备特殊需求的. 底层驱动移植前面两篇已经介绍.这里介绍顶层的调用过程.顶层在uboot/common/cmd_date.c /* * (C) Co ...

  8. [React] displayName for stateless component

    We can use 'displayName' on component to change its component tag in dev tool: import React from 're ...

  9. Quartz2D常见图形的绘制:线条、多边形、圆

    UI高级 Quartz2D http://ios.itcast.cn  iOS学院 掌握 drawRect:方法的使用 常见图形的绘制:线条.多边形.圆 绘图状态的设置:文字颜色.线宽等 图形上下文状 ...

  10. ZOJ Monthly, June 2014 解题报告

    A.Another Recurrence Sequence problemId=5287">B.Gears 题目大意:有n个齿轮,一開始各自为一组.之后进行m次操作,包含下面4种类型: ...