标记 | 描述 |
---|---|
|
注释 |
|
锚点——通常用来放一个超链接 |
|
对齐 |
|
定义文本体的边界 |
|
行分隔 |
|
将内容居中 |
|
定义一个表单 |
|
一级标题 |
|
定义文档首部的边界 |
|
定义HTML文档的边界 |
|
在表单中定义一个输入组件 |
|
一个新段落 |
|
HTML文档的标题 |
GET /socket.io/1/xhr-polling/cjJ4rr2VUk0aTC0JKKvG?t=1493719041095 HTTP/1.1\r\n
Host: s1-im-notify.csdn.net\r\n
Connection: keep-alive\r\n
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Maxthon/5.0.2.2000 Chrome/47.0.2526.73 Safari/537.36\r\n
Origin: http://write.blog.csdn.net\r\n
Accept: */*\r\n
DNT: 1\r\n
Referer: http://write.blog.csdn.net/postlist\r\n
Accept-Encoding: gzip, deflate\r\n
Accept-Language: zh-CN\r\n
GET /socket.io/1/xhr-polling/cjJ4rr2VUk0aTC0JKKvG?t=1493719041095 HTTP/1.1\r\n
为请求行 /socket.io/1/xhr-polling/cjJ4rr2VUk0aTC0JKKvG
:Web服务器上资源的路径。?t=1493719041095
:在GET请求中,参数(如果有)会追加到请求URL第一部分的后面,以”?”开头。各参数之间用”&”分隔。HTTP/1.1
:Web浏览器所请求的协议的版本。其余部分为请求首部:
Host: s1-im-notify.csdn.net\r\n
Connection: keep-alive\r\n
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Maxthon/5.0.2.2000 Chrome/47.0.2526.73 Safari/537.36\r\n
Origin: http://write.blog.csdn.net\r\n
Accept: */*\r\n
DNT: 1\r\n
Referer: http://write.blog.csdn.net/postlist\r\n
Accept-Encoding: gzip, deflate\r\n
Accept-Language: zh-CN\r\n
Accept表示可以接受的MIME类型。
POST /pollmessage HTTP/1.1\r\n
Host: p.f.360.cn\r\n
Accept: */*\r\n
Connection: Keep-Alive\r\n
Cache-Control: no-cache\r\n
Content-Length: 358\r\n
Content-Type: application/x-www-form-urlencoded\r\n
\r\n
[Full request URI: http://p.f.360.cn/pollmessage]
[HTTP request 1/1]
[Response in frame: 150751]
POST /pollmessage HTTP/1.1\r\n
:请求行 POST
:HTTP方法/pollmessage
:资源在Web服务器上的路径HTTP/1.1
:Web浏览器请求的协议的版本请求首部:
Host: p.f.360.cn\r\n
Accept: */*\r\n
Connection: Keep-Alive\r\n
Cache-Control: no-cache\r\n
Content-Length: 358\r\n
Content-Type: application/x-www-form-urlencoded\r\n
消息体(负载):
[Full request URI: http://p.f.360.cn/pollmessage]
[HTTP request 1/1]
[Response in frame: 150751]
体包含了让浏览器显示的具体内容。
HTTP/1.1 200 OK\r\n
Server: nginx\r\n
Date: Tue, 02 May 2017 13:01:11 GMT\r\n
Content-Type: application/octet-stream\r\n
Content-Length: 160\r\n
Connection: close\r\n
Cache-Control: no-cache\r\n
pragma: no-cache\r\n
\r\n
[HTTP response 1/1]
[Time since request: 0.117763000 seconds]
[Request in frame: 150745]
HTTP/1.1
:Web服务器使用的协议的版本200
:响应的HTTP状态码OK
:状态码的响应文本Content-Type: application/octet-stream
:MIME类型。MIME类型告诉浏览器要接收的数据是什么类型,这样浏览器才能知道如何显示这些数据。响应中必须有的一个首部。HTTP响应首部:
HTTP/1.1 200 OK\r\n
Server: nginx\r\n
Date: Tue, 02 May 2017 13:01:11 GMT\r\n
Content-Type: application/octet-stream\r\n
Content-Length: 160\r\n
Connection: close\r\n
Cache-Control: no-cache\r\n
pragma: no-cache\r\n
体:
[HTTP response 1/1]
[Time since request: 0.117763000 seconds]
[Request in frame: 150745]
http://code.thunisoft.com:80/media/asr-server/blob/master/asrServer/readme/interface/接口文档.md
http://
:协议,告诉服务器使用什么通信协议。code.thunisoft.com
:服务器:所请求物理服务器的唯一名。这个名字映射到一个唯一的IP地址。IP地址是一个数字,形式为”xxx.yyy.zzz.aaa”。在这里也可以指定一个IP地址而不是服务器名,不过服务器名更容易记。80
:端口,URL的这一部分是可选的。一个服务器可以支持多个端口。一个服务器应用由端口标识。如果在URL中没有指定的端口,默认端口则是端口80,而且很幸运,这正是Web服务器的默认端口。media/asr-server/blob/master/asrServer/readme/interface/接口文档.md
:路径:所请求资源在服务器上的路径。接口文档.md
:所请求内容的名字。这一部分是可选的,如果没有这一部分,大多数Web服务器都会默认地查找index.html。常用服务器应用TCP端口号:
应用 | 端口 |
---|---|
FTP | 21 |
Telnet | 23 |
SMTP | 25 |
Time | 37 |
HTTP | 80 |
POP3 | 110 |
HTTPS | 443 |
创建一个目录树:
/project1
/src
/classes
/etc
编写一个Ch1Servlet.java的servlet,把它放在src目录中:
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
public class Ch1Servlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
PrintWriter out = resp.getWriter();
java.util.Date today = new java.util.Date();
out.println("" +
"" +
"HF\'s Chapter1 Servlet
" +
"
" + today + "" + "");
}
}
创建一个部署文件(deployment descriptor,DD),名为web.xml,把它放在etc目录中。(可以从tomcat的例子中拷贝一份出来修改)
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<servlet>
<servlet-name>Chapter1 Servletservlet-name>
<servlet-class>Ch1Servletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>Chapter1 Servletservlet-name>
<url-pattern>/Serv1url-pattern>
servlet-mapping>
web-app>
在以后的Tomcat目录下建立这个目录树:
/tomcat
/webapps
/ch1
/WEB-INF
/classes
从project1目录编译servlet:
javac -classpath "G:\Tomcat 8.5\lib\servlet-api.jar" -d classes src/Ch1Servlet.java
把Ch1Servlet.class文件复制到WEB-INF/classes,再把web.xml文件复制到WEB-INF。
打开浏览器,键入:
http://localhost:8080/ch1/Serv1
每次更新servlet类或部署文件都需要关闭Tomcat。
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
// 99.9999%的servlet都是HttpServlet
public class Ch1Servlet extends HttpServlet {
// 在实际中,99.9%的servlet都会覆盖doGet()或doPost()方法
// servlet从这里拿到容器创建的请求和响应对象的引用
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
// 在servlet从容器得到的响应对象中,可以拿到一个PrintWriter。
// 使用这个PrintWriter能够将HTML文本输出到响应对象
PrintWriter out = resp.getWriter();
java.util.Date today = new java.util.Date();
out.println("" +
"" +
"HF\'s Chapter1 Servlet
" +
"
" + today + "" + "");
}
}
建立servlet名的映射,这有助于改善应用的灵活性和安全性。
: 内部名映射到完全限定类名
: 内部名映射到公共URL名
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<servlet>
<servlet-name>Chapter1 Servletservlet-name>
<servlet-class>Ch1Servletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>Chapter1 Servletservlet-name>
<url-pattern>/Serv1url-pattern>
servlet-mapping>
web-app>
/projects
/web
/beerV1
/etc
web.xml -- 配置文件
/lib -- 在这里放第三方JAR文件
/src -- 所有Java代码都放在src目录下
/com
/cynhard
/web -- 在这里放控制组件
BeerSelect.java
/model -- 在这里放模型组件
BeerExpert.java
/classes -- 与src对应,放置相应的.class文件
/com
/cynhard
/web
BeerSelect.class
/model
BeerExpert.class
/web -- 静态和动态视图组件放在这里
result.jsp
form.html
---------------- 特定于Tomcat的部分 ----------------
/Tomcat 8.5 -- Tomcat主目录
/webapps
/Beer-v1 -- Web应用的名字,在Tomcat解析URL是用到。
----------------- Servlet规范的部分 ----------------
form.html
result.jsp
/WEB-INF
web.xml -- 必须放在WEB-INF中
/lib
/classes
----------------- 特定于应用的部分 ------------------
/com -- 这个包结构与开发环境中使用的结构完全相同
/cynhard
/web
BeerSelect.class
/model
BeerExpert.class
4.1.1 编写开始页面
<html>
<body>
<h1 align="center">Beer Selection Pageh1>
<form method="POST" action="SelectBeer.do">
Select beer characteristics<p>
Color:
<select name="color" size="1">
<option value="light"> light option>
<option value="amber"> amber option>
<option value="brown"> brown option>
<option value="dark"> dark option>
select>
<br><br>
<center>
<input type="SUBMIT">
center>
form>
body>
html>
4.1.2 部署和测试开始页面
在开发环境中创建DD,保存到开发环境中的 /beerV1/etc/web.xml中。
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<servlet>
<servlet-name>Ch3 Beerservlet-name>
<servlet-class>com.cynhard.web.BeerSelectservlet-class>
servlet>
<servlet-mapping>
<servlet-name>Ch3 Beerservlet-name>
<url-pattern>/SelectBeer.dourl-pattern>
servlet-mapping>
web-app>
把DD文件拷贝到部署环境:/webapps/Beer-v1/WEB-INF/web.xml。
http://localhost:8080/Beer-v1/form.html
。4.2.1 控制器servlet的第1版
在开发环境的src/com/cynhard/web目录下创建BeerSelect.java,内容如下:
package com.cynhard.web; // 确保与前面创建的开发结构和部署结构匹配
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
// HttpServlet扩展了GenericSevlet,GenericServlet则实现了Servlet接口
public class BeerSelect extends HttpServlet {
// 我们使用doPost来处理HTTP请求,因为HTTP表单指出:method=POST
public void doPost(HttpServletRequest request,
HttpServletResponse response) throws IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("Beer Selection Advice
");
String c = request.getParameter("color");
out.println("
Got beer color " + c);
}
}
4.2.2 编译、部署和测试控制器servlet
编译servlet
javac -classpath "G:\Tomcat 8.5\lib\servlet-api.jar";classes;. -d classes src\com\cynhard\web\BeerSelect.java
-d
选项告诉编译器,把.class文件放在适当包结构中的classes目录下。
部署servlet
将开发环境的BeerSelect.class
拷贝到部署环境中: webapps/Beer-v1/WEB-INF/classes/com/cynhard/web/BeerSelect.class
测试servlet
http://localhost:8080/Beer-v1/form.html
4.3.3 构建和测试模型
package com.cynhard.model;
import java.util.*;
public class BeerExpert {
public List getBrands(String color) {
List brands = new ArrayList();
if (color.equals("amber")) {
brands.add("Jack Amber");
brands.add("Red Moose");
} else {
brands.add("Jail Pale Ale");
brands.add("Gout Stout");
}
return brands;
}
}
编译 :
javac -d classes -Xlint:unchecked src\com\cynhard\model\BeerExpert.java
将边编译后的BeerExpert.class放到部署目录:
\webapps\Beer-v1\WEB-INF\classes\com\cynhard\model
第2版servlet代码
package com.cynhard.web;
import com.cynhard.model.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
public class BeerSelect extends HttpServlet {
public void doPost(HttpServletRequest request,
HttpServletResponse response) throws IOException {
String c = request.getParameter("color");
// 实例化BeerExpert类,调用getBrands()
BeerExpert be = new BeerExpert();
List result = be.getBrands(c);
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("Beer Selection Advice
");
// 打印建议
Iterator it = result.iterator();
while (it.hasNext()) {
out.print("
try: " + it.next());
}
}
}
编译:
javac -classpath "G:\Tomcat 8.5\lib\servlet-api.jar";classes;. -d classes src\com\cynhard\web\BeerSelect.java
部署和测试
将编译的.class文件复制到部署环境:
\webapps\Beer-v1\WEB-INF\classes\com\cynhard\web
4.5.1 新建JSP,保存在开发环境下:\beerV1\web\result.jsp
。
<%@ page import="java.util.*" %>
<html>
<body>
<h1 align="center">Beer Recommendations JSPh1>
<p>
<%
List styles = (List)request.getAttribute("styles");
Iterator it = styles.iterator();
while (it.hasNext()) {
out.print("
try: " + it.next());
}
%>
body>
html>
将其拷贝到部署目录
\webapps\Beer-v1
4.5.2 改进servelt,调用JSP
package com.cynhard.web;
import com.cynhard.model.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
public class BeerSelect extends HttpServlet {
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
String c = request.getParameter("color");
// 实例化BeerExpert类,调用getBrands()
BeerExpert be = new BeerExpert();
List result = be.getBrands(c);
// 为请求对象增加一个属性,供JSP使用。
request.setAttribute("styles", result);
// 为JSP实例化一个请求分派器。
RequestDispatcher view = request.getRequestDispatcher("result.jsp");
// 使用请求分派器要求容器准备好JSP,并向JSP发送请求和响应。
view.forward(request, response);
}
}
编译、部署和测试:和之前的一样,这里略过。
时序图
声明周期中的三大重要时刻
方法 | 何时调用 | 作用 | 是否覆盖 |
---|---|---|---|
init() | servlet实例创建后,并在 servlet能为客户请求提供 服务之前,容器对servlet 调用init()。 |
使你在sevlet处理客户请求 之前有机会对其初始化。 |
有可能。 |
service() | 客户请求到来时,容器会 开始或分配一个新线程, 调用service()。 |
查看请求类型,决定调用 doGet()或者doPost()。 |
不需要。 |
doGet()和/或doPost() | service()根据请求的HTTP 方法调用doGet()或doPost() |
在这里写业务逻辑代码。 | 至少覆盖其一。 |
service()方法总是在自己的栈中调用。容器运行多个线程来处理对一个servlet的多个请求。
method="POST"
是POST,method=”GET”或者没有method都是GET。获取参数
获取单个参数:
String param1 = request.getParameter("param1");
String param2 = request.getParameter("param2");
如果参数是数组:
String[] param = request.getParameterValues("param")
客户的平台和浏览器信息
String client = request.getHeader("User-Agent");
与请求相关的cookie
Cookie[] cookies = request.getCookies();
与客户相关的会话(session)
HttpSession session = request.getSession();
请求的HTTP方法
String method = request.getMethod();
请求的输入流
InputStream input = request.getInputStream();
可以用PrintWriter对象或OutputStream对象输出数据,PrintWriter是对OutputStream的封装,用来写入文本数据。OutputStream用来写入二进制数据。PrintWriter通过getWriter()方法得到。OutputStream对象由getOutputStream()方法得到:
PrintWriter writer = response.getWriter();
OutputStream out = response.getOutputStream();
setHeader()设置响应头部,addHeader()增加响应头部。setHeader()会覆盖现有的值。addHeader()会增加另外一个值。
重定向是一个字符串,如果不以/开头,则重定向以当前目录为基路径。如果以/
开头,则重定向以Web应用为基路径。
/
开头/
开头不能在写到响应之后再调用sendRedirect()。
请求分派交给服务器上的其他部分处理。
RequestDispatcher view = request.getRequestDispatcher("result.jsp");
view.forward(request, response);
Servlet初始化参数:
在DD文件中:
<servlet>
<servlet-name>Ch3 Beerservlet-name>
<servlet-class>com.cynhard.web.BeerSelectservlet-class>
<init-param>
<param-name>myEmailparam-name>
<param-value>cynhard85@126.comparam-value>
init-param>
servlet>
在servlet代码中:
writer.println(getServletConfig().getInitParameter("myEmail"));
在servlet初始化之前不能使用servlet初始化参数。
上下文初始化参数
DD中:
<servlet>
<servlet-name>Ch3 Beerservlet-name>
<servlet-class>com.cynhard.web.BeerSelectservlet-class>
servlet>
<context-param>
<param-name>myEmailparam-name>
<param-value>cynhard85@126.comparam-value>
context-param>
Servlet中:
out.println(getServletContext().getInitParameter("myEmail"));
是针对整个应用的,因此放在所有
之外。
ServletContextListener使用
listener 代码:
package com.cynhard.web;
import javax.servlet.*;
public class MyServletContextListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
ServletContext sc = event.getServletContext();
// ...
}
public void contextDestroyed(ServletContextEvent event) {
// ...
}
}
DD:
<listener>
<listener-class>
com.cynhard.MyServletContextListener
listener-class>
listener>
不放在
元素内部。
场景 | 监听者 | 事件类型 |
---|---|---|
你想知道一个Web应用 上下文中是否增加、删 除或替换了一个属性 |
javax.servlet.ServletContextAttributeListener | ServletContextAttributeEvent |
你想知道有多少个并发 用户。也就是说,你想 跟中活动的会话。 |
javax.servlet.http.HttpSessionListener | HttpSessionEvent |
每次请求到来时你都想 知道,以便建立日志记 录。 |
javax.servlet.ServletRequestListener | ServeltRequestEvent |
增加、删除或替换一个 请求属性时你希望能够 知道。 |
javax.servlet.ServletRequestAttributeListener | ServletRequestAttributeEvent |
你有一个属性类(这个 类表示的对象将放在一 个属性中),而且你希 望这个类型的对象在绑 定到一个会话或从会话 删除时得到通知。 |
javax.servlet.http.HttpSessionBindingListener | HttpSessionBindingEvent |
增加、删除或替换一个 会话属性时你希望能够 知道。 |
javax.servlet.http.HttpSessionAttributeListener | HttpSessionBindingEvent |
你想知道是否创建或撤 销了一个上下文 |
javax.servlet.ServletContextListener | ServletContextEvent |
你有一个属性类,而且希 望这个类型的对象在其 绑定的会话迁移到另一 个JVM时得到通知。 |
javax.servlet.http.HttpSessionActivationListener | HttpSessionEvent |
属性和参数
2 | 属性 | 参数 |
---|---|---|
类型 | 应用/上下文 请求 会话 |
应用/上下文初始化参数 请求参数 Servlet初始化参数 |
设置方法 | setAttribute(String name, Object value) | 不能设置应用和Servlet初始化参数。它们都在DD中设置。 |
返回类型 | Object | String |
获取方法 | getAttribute(String name) | getInitParameter(String name) |
属性的三个作用域:上下文、请求和会话
属性API
Object getAttribute(String name)
void setAttribute(String name, Object value)
void removeAttribute(String name)
Enumeration getAttributeNames()
不能通过同步服务方法的方式保护上下文属性。而是对上下文加锁。
// 错误!上下文对象仍可以通过其他servlet访问
public synchronized void doGet(...)
// 正确,对上下文加锁
synchronized(getServeltContext()) {
//...
}
HttpSession session = request.getSession();
synchronized(session) {
// ...
}
// 从ServletRequest得到RequestDispatcher
// 参数如果以/开头,则从Web应用的根开始找
// 如果不是以/开头,则从当前位置(请求发生的位置)开始找
RequestDispatcher view = request.getRequestDispatcher("result.jsp");
// 从ServletContext得到RequestDispatcher
// 路径必须以/开头,只能从Web应用的根开始找
ReqeustDispatcher view = getServletContext().getRequestDispaatcher("/result.jsp");
// 在RequestDispatcher上调用forward()分派请求
view.forward(request, response);
request.getSession()
获取Session。session.isNew()
返回是否新建的Session。request.getSession(fase)
获取已有的会话。如果得到返回HtteSession,否则返回null。URL重写API:
response.encodeURL("/BeerTest.do")
response.encodeRedirectURL("/BeerTest.do")
不能对静态页面完成URL重写。因此必须在运行时动态生成HTML。
标签可以很容易的完成这个工作。要点
要对一个URL编码,需要调用response.encodeURL(aString)。
out.println("click me");
没有办法对静态页面完成自动的URL重写,所以,如果你依赖于会话,就必须使用动态生成的页面。
它做什么 | 你用它做什么 | |
---|---|---|
getCreationTime() | 返回第一次创建会话的时间。 | 得出这个会话有多“老”。你可能想把某些会话的寿命限制为一个固定的时间。例如,你可能会说“一旦登陆,就必须在10分钟之内完成这个表单……” |
getLastAccessedTime() | 返回容器最后一次得到包含这个会话ID的请求后过去了多长时间(毫秒数) | 得出客户最后一次访问这个会话是什么时候。可以用这个方法来确定客户是否已经离开很长时间,这样就可以向客户发出一封email,询问他们是否还回来。或者可以调用invalidate()结束会话。 |
setMaxInactiveInterval() | 指定对于这个会话客户请求的最大间隔时间(秒数)。 | 如果已经过去了指定时间,而客户未对这个会话做出任何请求,就会导致会话被撤销。可以用这个方法减少服务器中无用的会话。 |
getMaxInactiveInterval() | 返回对于这个会话客户请求的最大间隔时间(秒数)。 | 得出这个会话可以保持多长时间不活动但仍“存活”。可以使用这个方法来判断一个不活动的客户在会话撤销之前还有多长的“寿命”。 |
invalidate() | 结束会话。当前存储在这个会话中的所有会话属性也会解除绑定。 | 如果客户已经不活动,或者你知道会话已经结束,可以用这个方法杀死(撤销)会话。会话实例本身可能由容器回收,但是这一点我们并不关心。置无效意味着会话ID不再存在,而且属性会从会话对象删除。 |
<session-config>
<session-timeout>15session-timeout>
session-config>
session.setMaxInactiveInterval(20 * 60);
创建一个新Cookie
Cookie cookie = new Cookie("username", name);
设置cookie在客户端上存活多久
// 以秒为单位,如果-1,则浏览器退出时cookie消失。
cookie.setMaxAge(30 * 60);
把cookie发送到客户
response.addCookie(cookie);
从客户请求得到cookie(或多个cookie)
Cookie[] cookies = request.getCookies();
<% out.println(""); %>
导入单个包,指令最后没有分号
<%@ page import="foo.*" %>
导入多个包,逗号分隔
<%@ page import="foo.*,java.util.*" %>
<%= Counter.getCount() %>
需要分号结束。
<%! int count = 0; %>
API | 隐式对象 |
---|---|
JspWriter | out |
HttpServeltRequest | request |
HttpServletResponse | response |
HttpSession | session |
ServletContext | application |
ServletConfig | config |
Throwable | exception |
PageContext | pageContext |
Object | page |
<%-- JSP注释 --%>
DD
<servlet>
<servlet-name>MyTestInitservlet-name>
<jsp-file>/TestInit.jspjsp-file>
<init-param>
<param-name>emailparam-name>
<param-value>cynhard85@126.comparam-value>
init-param>
servlet>
<servlet-mapping>
<servlet-name>MyTestInitservlet-name>
<url-parttern>/TestInit.jspurl-parttern>
servlet-mapping>
覆盖jspInit()
<%!
public void jspInit() {
ServletConfig sConfig = getServletConfig();
String emailAddr = sConfig.getInitParameter("email");
ServletContext ctx = getServletContext();
ctx.setAttribute("mail", emailAddr);
}
%>
servlet中 | JSP中 | |
---|---|---|
应用 | getServletContext().setAttribute(“foo”, barObj); | application.setAttribute(“foo”, barObj); |
请求 | request.setAttribute(“foo”, barObj); | request.setAttribute(“foo”, barObj); |
会话 | request.getSession().setAttribute(“foo”, barObj); | session.setAttribute(“foo”, barObj); |
页面 | 不适用! | pageContext.setAttribute(“foo”, barObj); |
<%-- 设置一个页面作用域属性 --%>
<% Float one = new Float(42.5); %>
<% pageContext.setAttribute("foo", one); %>
<%-- 获得一个页面作用域属性 --%>
<%= pageContext.getAttribute("foo"); %>
<%-- 使用pageContext设置一个会话作用域属性 --%>
<% Float two = new Float(22.4); %>
<% pageContext.setAttribute("foo", two, PageContext.SESSION_SCOPE); %>
<%-- 使用pageContext获得一个会话作用域属性 --%>
<%= pageContext.getAttribute("foo", PageContext.SESSION_SCOPE); %>
<%-- 等价于: --%>
<%= session.getAttribute("foo"); %>
<%-- 使用pageContext获得一个应用作用域属性 --%>
<%= pageContext.getAttribute("mail", PageContext.APPLICATION_SCOPE); %>
<%-- 等价于: --%>
<%= application.getAttribute("mail"); %>
<%-- 使用pageContext,即使不知道作用域也可以查找一个属性 --%>
<%-- 查找顺序:page->request->session->application --%>
<%= pageContext.findAttribute("foo"); %>
<%@ page import="foo.*" session="false" %>
定义页面的特定的属性,以及这个页面是否要有隐式的会话对象。
属性 | 意义 |
---|---|
import | 定义Java import语句 |
isThreadSafe | 定义生成的servlet是否需要实现SingleThreadModel(bad idea)。 |
contentType | 定义JSP响应的MIME类型。 |
isELIgnored | 定义转换这个页面时是否忽略EL表达式。 |
isErrorPage | 定义当前页面是否是另一个JSP的错误页面。 |
errorPage | 定义一个资源的URL,如果有未捕获到的Throwable,就会发送到这个资源。 |
language | 定义scriptlet、表达式和声明中使用的脚本语言。 |
extends | JSP会变成一个servlet类,这个属性则定义了这个类的超类。 |
session | 定义页面是否有一个隐式的session对象。默认值为true。 |
buffer | 定义隐式out对象(JspWriter的引用)如何处理缓存。 |
autoFlush | 定义缓存的输出是否自动刷新输出。默认值是true。 |
info | 定义放到转换后页面中的串,这样就能使用所生成servlet继承的getServletInfo()方法来得到这个信息。 |
pageEncoding | 定义JSP的字符编码。默认为“ISO-8859-1” |
<%@ taglib tagdir="/WEB-INF/tags/cool" prefix="cool" %>
定义JSP可以使用的标记库。
<%@ include file="wickedHeader.html" %>
定义在转换时增加到当前页面的文本和代码。
EL和Java比较:
${application.mail}
<%= application.getAttribute("mail") %>
让JSP禁用脚本元素(scriptlet、Java表达式或声明):
<jsp-config>
<sp-property-group>
<url-parttern>*.jspurl-parttern>
<scripting-invalid>truescripting-invalid>
sp-property-group>
jsp-config>
忽略EL(默认是启用的):
通过DD:
<jsp-config>
<sp-property-group>
<url-parttern>*.jspurl-parttern>
<el-ignored>trueel-ignored>
sp-property-group>
jsp-config>
通过page指令:
<%@ page isELIgnored="true" %>
<jsp:include page="wickedFooter.jsp" />
set var="rate" value="32" />
Bean应用:
servlet中:
Person person = new Person();
person.setName("Gopher");
request.setAttribute("person", person);
jsp中:
id="person" class="com.cynhard.model.Person" scope="request" />
name="person" property="name" />
分解:
标识标准动作id="person"
声明bean对象的标识符。这对应于以下servlet代码中所用的名:request.setAttribute("person", p);
class="com.cynhard.model.Person"
声明bean对象的类类型。scope="request"
标识这个bean对象的属性作用域。jsp:getProperty
标识标准动作name="person"
标识具体的bean对象。这与
标记的“id”值匹配。property="name"
标识属性中的性质名(也就是bean类中获取方法和设置方法对应的性质)。
如果找不到属性对象,则会创建一个。
可以用
设置属性。
name="person" property="name" value="Cynhard" />
利用
体,可以有条件地运行代码,只有找不到bean属性,而且创建了一个新bean是才会运行体中的代码。
<jsp:useBean id="person" class="com.cynhard.model.Person" scope="request">
<jsp:setProperty name="person" property="name" value="Cynhard" />
jsp:useBean>
Bean标记会自动转换基本类型的性质
增加一个type属性class为对象类型。type为引用类型。
"person" type="foo.Person" class="foo.Employee" scope="page">
type可以是class类型、抽象类型或者是一个接口,只要能用作为bean对象class类型的声明引用类型,都可以指定为type。
type x = new class()
"person" class="foo.Employee" scope="page"/>
等价于:
id="person" class="foo.Employee"/>
利用param属性,可以把bean的性质值设置为一个请求参数的值。只需指定请求参数!
TestBean.jsp:
<jsp:useBean id="person" type="foo.Person" clas="foo.Employee">
<jsp:setProperty name="person" property="name" param="userName"/>
jsp:useBean>
直接获取userName的值:
<form acton="TestBean.jsp">
name: <input type="text" name="userName"/>
...
form>
如果请求参数名与bean性质名匹配,就不需要在
标记中为该性质指定值。
TestBean.jsp,不再需要param。
<jsp:useBean id="person" type="foo.Person" clas="foo.Employee">
<jsp:setProperty name="person" property="name"/>
jsp:useBean>
直接获取userName的值:
<form acton="TestBean.jsp">
name: <input type="text" name="name"/>
...
form>
如果所有请求参数名都与bean性质名匹配,则
中可以用property=*
来获取所有请求参数的值。
name="person" property="*"/>
使用EL,打印嵌套性质变得非常容易……换句话说,可以很轻松地打印性质的性质。
${person.dog.name}
EL表达式总是放在大括号里,而且前面有一个美元符前缀。
表达式中第一个命名变量可以是一个隐式对象,也可以是一个属性。
pageScope requestScope sessionScope applicationScope param paramValues header headerValues cookie initParam pageContext
。在所有隐式对象中,只有pageContext不是Map。这是pageContext对象的实际引用。使用点号操作符访问性质和映射值:
[]
就像是更好的点号:
${person["name"]}
[]
左边可以是List、数组、Map、Bean。[]
里面可以是键、索引、属性名。
如果不是String直接量,就会计算。
${musicMap[Ambient]} // 查找一个名为"Ambient"的属性。
${musicMap["Ambient"]}
方括号内可以使用嵌套表达式
${musicMap[MusicType[0]]}
点号后面不能接索引:${foo.1}是不行的。如果不能用作为Java代码中的变量名,就不能把它放在点号后面。
HTML中:
<form action="TestBean.jsp">
Name: <input type="text" name="name">
ID#: <input type="text" name="empID">
First food: <input type="text" name="food">
Second food: <input type="text" name="food">
<input type="submit">
form>
JSP中:
Request param name is: ${param.name}<br>
Request param empID is: ${param.empID}<br>
Request param food is: ${param.food}<br>
First food request param: ${paramValues.food[0]}<br>
Second food request param: ${paramValues.food[1]}<br>
Request param name: ${paramValues.name[0]}
得到“host”首部:
${header["host"]}
${header.host}
使用requestScope会得到请求属性,而不是request性质。要得到request性质,需要通过pageContext。
${pageContext.request.method}
打印“useName”Cookie的值:
脚本:
<%
Cookie[] cookies = request.getCookies();
for (int i = 0; i < cookies.length; i++) {
if ((cookies[i].getName()).equals("userName")) {
out.println(cookies[i].getValue());
}
}
%>
EL:
${cookie.userName.value}
打印一个上下文初始化参数:
DD:
<context-param>
<param-name>mainEmailparam-name>
<parma-value>cynhard85@126.comparam-value>
context-param>
脚本:
<%= application.getInitParameter("mainEmail") %>
EL:
${initParam.mainEmail}
编写有一个公共静态方法的Java类。
放在WEB-INF/classes中
package foo;
public class DiceRoller {
public static int rollDice() {
return (int)((Math.random() * 6) +1);
}
}
编写一个标记库描述文件(TLD)。
确保JSP中taglib指令包含的uri属性与TLD中的
元素匹配。
<taglib>
<tlib-version>1.2tlib-version>
<uri>DiceFunctionsuri>
<function>
<name>rollItname>
<function-class>foo.DiceRollerfunction-class>
<function-signature>int rollDice()function-signature>
function>
taglib>
在JSP中放一个taglib指令。
taglib指令告诉容器,“我想使用这个TLD,另外,在JSP中,使用这个TLD中的一个函数时,我想用这个名字作为前缀……”
<%@ taglib prefix="mine" uri="DiceFunctions"%>
<html><body>
${mine:rollIt()}
body>html>
使用EL调用函数。
${prefix:name()}
算术操作符
加法 +
减法 -
乘法 *
除法 /和div
取模 %和mod
逻辑操作符
与 &&和and
或 ||和or
非 !和not
关系操作符
等于 == 和eq
不等于 !=和ne
小于 <和lt
大于>和gt
小于等于 <=和le
大于等于 >=和ge
$
)前缀:${expression}
${foo.bar}
可以得到bar的值,在此bar是Map foo的Map键名,或者bar是bean foo的一个性质。放在点号操作符右边的东西必须遵循Java的标识符命名规则!(换句话说,必须以一个字母,下划线或美元符号开头,第一个字符后面可以有数字,但是不能邮其他字符。)${foo.1}
就不允许。[]
操作符比点号功能更强大,因为利用[]
可以访问数组和List,可以把包含命名变量的表达式放在中括号里,而且可以做任意层次的嵌套,只要你受得了。${musicList[0]}
或${musicList["0"]}
来访问列表中的第一个值。EL并不关心列表索引加不加引号。${foo:rollIt()}
并不意味着包含函数的类中肯定有一个名为rollIt()的方法。
元素声明一个函数,包括函数的
(rollIt()),完全限定类
,以及
,其中包括返回类型以及方法名和参数表。<%@ taglib prefix="mine" uri="/WEB-INF/foo.tld"%>
<%@ include file="Header.jsp"%>
标准动作:
标准动作在运行时发生。
标准动作在运行时插入“Header.jsp”的相应。
是位置敏感的。
定制包含的内容包含的页面:
include page="Header.jsp">
param name="subTitle" value="Hello"/>
include>
被包含的页面:
<strong>${param.subTitle}strong>
标准动作<% if (request.getParameter("useName") == null) { %>
<jsp:forward page="HandleIt.jsp"/>
<% } %>
如果发生了转发,转发前些的所有内容都不会出现。
if test="${empty param.userName}">
"HandleIt.jsp"/>
if>
标准动作会定义一个变量,它可能是一个现有bean属性的引用,如果还不存在这样一个bean,则会创建一个新的bean,这个变量就是新bean的引用。
必须有一个“id”属性,这个属性声明了JSP中引用bean时所用的变量名。
中没有“scope”属性,作用域默认为页面(page)作用域。
中放了一个“type”属性,bean必须能强制转换成这种类型。
标记可以有一个体,体中的内容会有条件地运行,只有当创建一个新的bean作为
的结果时,才会运行体中的内容[这说明,指定(或默认)作用域中不存在有该“id”的bean]。
体的主要作用是使用
设置新bean的性质。
必须有一个name属性(它要与
的“id”匹配),还要有一个“property”属性。“property”属性必须是一个具体的性质名,或者是通配符“*”。
标记中使用“param”属性。
动作使用自省将“性质”匹配到一个JavaBean设置方法。如果性质是“*”,JSP将迭代处理所有请求参数来设置JavaBean性质。
标准动作会自动完成转换。
标准动作),可以利用可重用的组件创建页面。
标准动作在运行时把被包含页面的响应包含到原页面中。所以如果包含的内容在部署之后可能更新,include标准动作就很适用,此时不适用include指令。
的体中使用
标准动作设置(或替换)请求参数,用来定制所包含的文件。
也可以用在
标记的体中。
只能放在
或
标准动作中。
中使用的参数名已经有一个值(作为请求参数),新值会覆盖原来的值。否则,就会向请求增加一个新的请求参数。
标准动作可以把请求转发到同一个Web应用中的另一个资源(就像使用RequestDispatcher一样)。
用于输出,可以通过escapeXml指定是否转义XML字符,默认值为true
out value='${pageContext.currentTip}' escapeXml='true'/>
可以指定默认值:
out value='${user}' default='guest'/>
用于循环:
<c:forEach var="movie" items="${movieList}">
<tr><td>${movie}td>tr>
c:forEach>
可以嵌套
if test="${useType eq 'member'}">
"inputComments.jsp"/>
if>
、
、
"${user} == 'admin'">
...
"${user} == 'guest'">
...
...
“var”用于设置属性。可以有体也可以没体。
set var="userLevel" scope="session" value="Cowboy"/>
set var="userLevel" scope="session">
Cowboy
set>
“target”用于设置bean性质或Map值。可以有体也可以没体。
set target="${PetMap}" property="dogName" value="Clover"/>
set target="${person}" property="name">
${foo.name}
set>
中不能同时有“var”和“target”属性。
${bean.notAProperty}
也会抛出一个异常。
删除属性:
var="userStatus" scope="request">
和
包含内容
<c:import url="http://www.cynhard.com/index.html"/>
可以到包含应用之外的内容
定制包含的内容<c:import url="Header.jsp">
<c:param name="subTitle" value="We are good"/>
c:import>
在需要时重写URL
<a href=" ">Click herea>
URL需要编码时,可以在体内写参数
value="/inputComments.jsp" var="inputURL">
param name="firstName" value="${first}"/>
param name="lastName" value="${last}"/>
错误页面(errorPage.jsp):
<%@ page isErrorPage="true"%>
处理页面:
<%@ page errorPage="errorPage.jsp" %>
通过异常配置错误页面
<error-page>
<exception-type>java.lang.Throwableexception-type>
<location>/errorPage.jsplocation>
error-page>
通过状态码配置错误页面
<error-page>
<error-code>404error-code>
<location>/notFoundError.jsplocation>
error-page>
<%@ page isErrorPage="true"%>
...
${pageContext.exception}
捕获异常捕获并吞掉异常
<c:catch>
<% int x = 10/0; %>
c:catch>
获取异常对象
catch var="myException">
<% int x = 10/0; %>
catch>
${myException.message}
TLD文件
<taglib>
<tlibversion>1.0tlibversion>
<jspversion>1.1jspversion>
<shortname>Tag Library for Openfire 2.0shortname>
<uri>http://www.igniterealtime.org/uri>
<info>Tab Library for Openfire Admin Consoleinfo>
<tag>
<description>some thingdescription>
<name>tabsname>
<tagclass>org.jivesoftware.admin.TabsTagtagclass>
<bodycontent>JSPbodycontent>
<info />
<attribute>
<name>cssname>
<required>falserequired>
<rtexprvalue>truertexprvalue>
attribute>
<attribute>
<name>currentcssname>
<required>falserequired>
<rtexprvalue>truertexprvalue>
attribute>
tag>
taglib>
解析
<tlibversion>1.0tlibversion>
<shortname>Tag Library for Openfire 2.0shortname>
<uri>http://www.igniterealtime.org/uri>
<description>some thingdescription>
<name>tabsname>
<tagclass>org.jivesoftware.admin.TabsTagtagclass>
<bodycontent>JSPbodycontent>
<attribute>
<name>cssname>
<required>falserequired>
<rtexprvalue>truertexprvalue>
attribute>
标记的属性
<name>cssname>
<required>falserequired>
<rtexprvalue>truertexprvalue>
jsp
<%@ taglib prefix="mine" uri="http://www.igniterealtime.org/"%>
...
"${userName}"%>
解析
prefix="mine"
uri="http://www.igniterealtime.org/"
http://www.igniterealtime.org/
mine:tabs
tabs
css="${userName}"
css
true
,因此这里可以放置表达式:${useName}
// SimpleTagSupport实现了定制标记所要完成的工作。
public class AdvisorTagHandler extends SimpleTagSupport {
// JSP使用TLD中声明的名字调用标记时,容器会调用doTag()。
public void doTag() throws JspException, IOException {
// ...
}
// 容器调用这个方法将值设置为标记属性的值。它使用JavaBean性质命名约定得出应该向setUser()方法发送一个“user”属性。
public void setUser(String user) {
}
}
或
的值为false,则不能在属性值中用表达式。属性的值允许rtexprvalue时,可以使用3种表达式。
EL表达式
"${userName}"/>
脚本表达式
<mine:advide user='<%= request.getAttribute("username") %>' />
标准动作
<mine:advice>
<jsp:attribute name="user">${userName}jsp:attribute>
mine:advice>
的取值
empty
不能有体scriptless
不能有脚本元素(scriptlet、脚本表达式和声明),但是可以是模板文本和EL,还可以是定制和标准动作。tagdependent
标记体要看作是纯文本,所以不会计算EL,也不会触发标记/动作。JSP
能放在JSP中的东西都能放在这个标记体中没有体的标记,有3种调用方法
在开始和结束之间只有
标记
<mine:advice>
<jsp:attribute name="user">${userName}jsp:attribute>
mine:advice>
与taglib指令中uri值之间的匹配。uri不一定是具体标记处理器的位置。