关于JSP
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方法的内部使用, 因为这些变量实际上都是在其内部定义的) :
- out : Servlet中需要通过resp.getWriter()来获得.
- request, response : Servlet中作为doGet/doPost/... 等方法的参数传入.
- session : 即Servlet中的HttpSession, 在Servlet通过req.getSession()来获得.
- application : Servlet中通过getServletContext()来获得
- config : Servlet中通过getServletConfig()来获得. (没错, JSP也可以设置初始化参数, 具体设置方法在后面提到)
- 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, 我们可以通过以下隐式对象来设置属性 :
- application 对应 ServletContext
- session 对应 HttpSession
- request 对应 HttpServletRequest
- 这里多了一个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中的隐式对象 :
- pageScope, requestScope, sessionScope, applicationScope这4个分别对应4个作用域下的保存属性的map
- param, paramValues 这是http请求参数的map, 后者用于存在多个同名参数情况.
- header, headValues 这是请求首部的map
- cookie 关于cookie的map, Servlet提供的是一个数组, 所以这里比Servlet要方便.
- initParam 这个不是Servlet的初始化参数而是context的初始化参数, 也就是整个应用的初始化参数的map.
- 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的更多相关文章
- myeclipse学习总结一(在MyEclipse中设置生成jsp页面时默认编码为utf-8编码)
1.每次我们在MyEclispe中创建Jsp页面,生成的Jsp页面的默认编码是"ISO-8859-1".在这种情况下,当我们在页面中编写的内容存在中文的时候,就无法进行保存.如下图 ...
- jsp前端实现分页代码
前端需要订一page类包装,其参数为 private Integer pageSize=10; //每页记录条数=10 private Integer totalCount; //总记录条数 priv ...
- jsp中出现onclick函数提示Cannot return from outside a function or method
在使用Myeclipse10部署完项目后,原先不出错的项目,会有红色的叉叉,JSP页面会提示onclick函数错误 Cannot return from outside a function or m ...
- jsp页面无法识别el表达式的解决方案
今天在写一个springmvc的小demo时,碰到一个问题,在jsp页面中书写为${user.username}的表达式语言,在浏览器页面中仍然显示为${user.username},说明jsp根本不 ...
- 浅谈JSP中include指令与include动作标识的区别
JSP中主要包含三大指令,分别是page,include,taglib.本篇主要提及include指令. include指令使用格式:<%@ include file="文件的绝对路径 ...
- 浅谈JSP注释
HTML注释 JSP文件是由HTML尿急和嵌入的Java程序片段组成的,所以在HTML中的注释同样可以在JSP文件中使用.注释格式:<!--注释内容--> <!-- 欢迎提示信息! ...
- JSP 标准标签库(JSTL)
JSP 标准标签库(JSTL) JSP标准标签库(JSTL)是一个JSP标签集合,它封装了JSP应用的通用核心功能. JSTL支持通用的.结构化的任务,比如迭代,条件判断,XML文档操作,国际化标签, ...
- Nginx服务器之Nginx与tomcat结合访问jsp
本文使用linux centos系统 本文概述: JSP是一种动态网页技术标准.使用的方式是在HTML文件中插入程序段和JSP标记,而形成JSP文件.使用JSP开发WEB应用可以跨平台开发.但jsp需 ...
- 基于jsp+servlet图书管理系统之后台万能模板
前奏: 刚开始接触博客园写博客,就是写写平时学的基础知识,慢慢发现大神写的博客思路很清晰,知识很丰富,非常又价值,反思自己写的,顿时感觉非常low,有相当长一段时间没有分享自己的知识.于是静下心来钻研 ...
- JSP页面跳转的几种实现方法
使用href超链接标记 客户端跳转 使用JavaScript 客户端跳转 提交表单 客户端跳转 使用response ...
随机推荐
- iOS开发webView的使用二
#import "ViewController.h" @interface ViewController ()<UIWebViewDelegate> @property ...
- RGCDQ(线段树+数论)
题意:求n和m之间的全部数的素因子个数的最大gcd值. 分析:这题好恶心.看着就是一颗线段树.但本题有一定的规律,我也是后来才发现,我还没推出这个规律.就不说了,就用纯线段树解答吧. 由于个点数都小于 ...
- [Grid Layout] Use auto-fill and auto-fit if the number of repeated grid tracks is not to be def
What about the situation in which we aren’t specifying the number of columns or rows to be repeated? ...
- 自旋锁解决StackOverflowError案例
本节笔者分享一个在实际工作中遇到的栈内存溢出(StackOverflowError)问题,以及其解决方案. 问题介绍:笔者负责的一个Java Web项目在启动的时候,需要有一些初始化操作,而接下来的代 ...
- Birt
http://www.eclipse.org/birt/ 咖啡图 http://www.kafeitu.me/activiti/2012/05/26/kft-activiti-demo.html
- Color the ball(杭电1556)
Color the ball Time Limit : 9000/3000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other) Tota ...
- 【hdu 1517】A Multiplication Game
Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s) ...
- HDU 1502 - dp + 压位
传送门 题目大意: 3*n的字符串,A.B.C分别有n个,w(X)代表X字母出现的次数,要求该字符串的所有前缀中w(A) >= w(B) >= w(C),问合法方案数有多少. 题目分析: ...
- java中<T> T和T的区别?
如果你希望 getMax 方法的返回值类型为 T,就要这样去定义getMax方法: public T getMax() 如果你希望 getMax 方法返回值的类型由调用者决定,那么就这么去定义 get ...
- UWP 和 WPF 对比
原文:UWP 和 WPF 对比 本文告诉大家 UWP 和 WPF 的不同. 如果在遇到技术选择或者想和小伙伴吹的时候可以让他以为自己很厉害,那么请继续看. 如果在看这文章还不知道什么是 UWP 和 W ...