《head first jsp》笔记

1. get 和post请求的区别
1.1 get请求的请求地址有一定的长度限制,请求的参数也是在请求的地址栏中显示。传递的数据量最大限制为2K
1.2 get请求是向服务器请求数据,post请求是向服务器传递数据
1.3 get限制Form表单的数据集的值必须为ASCII字符;而Post支持整个ISO10646字符集。
1.4 get是不安全的,因为在传输过程,数据被放在请求的URL中,而如今现有的很多服务器、代理服务器或者用户代理都会将请求URL记录到日志文件中,然后放在某个地方,这样就可能会有一些隐私的信息被第三方看到。另外,用户也可以在浏览器上直接看到提交的数据,一些系统内部消息将会一同显示在用户面前。Post的所有操作对用户来说都是不可见的。将数据放在消息体中

2.HTTP响应剖析
HTTP/1.1 200 OK //web服务器正在使用的协议版本 响应的HTTP状态码 状态码文本版本
CONTENT-TYPE:text/html //告诉浏览器要接受的是什么数据类型 也就是传说中的MIME类型
……

3.常见TCP端口
FTP:21, TELNET:23, SMTP:25, TIME:37,HTTP:80, POP3:110, HTTPS:443
0-1023的端口以及被保留,由一些知名的服务使用

4.http代表超文本传输协议,运行在TCP/IP之上

5.servlet的生命周期
1.加载类—2.实例化类—3.init()—4.Service()—5.doXXX()—-6.destroy()
5.1 容器只会加载一个servlet,多个对同一servlet的请求会启用多个线程来处理,每个线程对应一个全新的请求和响应对象
5.2 在步骤1,2,3只会运行一次,4,5,6根据请求书不同有多个对象在运行。init()在一个servlet一生中只运行一次。
5.3 每个servlet都有一个servletConfig对象:只要勇于读取一些配置参数,在web.xml中配置的参数

6.servletConfig 和ServletContext之间的区别
6.1 servletconfig:
从一个servlet被实例化后,对所有客户端在所有时候访问有效,但仅对本servlet 有效,一个servlet的servletconfig对象不能被另一个servlet访问。
6.2 servletcontext:
对所有servlet,所有人在所有时间都有效,这才是真正全局的对象。
6.3 用处
如果是整个系统的配置的话,那么就可以设置为servletContext的参数,如系统编码等
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:bme.service.xml
/WEB-INF/conf/global.datasource.xml
/WEB-INF/conf/*.service.xml /WEB-INF/conf/*.web.xml
/WEB-INF/console/conf/*.web.xml
/WEB-INF/console/conf/*.service.xml
/WEB-INF/frameset/conf/*.web.xml
/WEB-INF/frameset/conf/*.service.xml /WEB-INF/*.web.xml
classpath:org/codehaus/xfire/spring/xfire.xml
classpath:cmp/spring/cmp-spring-integration-startup.xml
classpath:iManager/spring/repository_service.xml
</param-value>
</context-param>
……….
</web-app>

若是某个单独servlet的配置项的话,可以设置为servletConfig的参数,如某个读取文件的servlet的目录地址等
<servlet>
<servlet-name>getatt</servlet-name>
<servlet-class>mail.getattservlet</servlet-class>
<init-param>
<param-name>abspath</param-name>
<param-value>/usr/mail/ax/axman/maildir/</param-value>
</init-param>
</servlet>
只能这个servlet能获取这些参数,不同servlet之间不能获取

实际上ServletContext的比ServletConfig的使用范围广很多, ServletConfig一般只用于获取Servlet的初始化参数,而ServletContext的作用是与Web Container交互,除了可以用于获取Web Application的全局初始化参数外,还可以获取Servlet的元数据,设置共享属性,获取属性值,获取外部资源等,另外当Web Application使用分布式部署时(在web.xml 中使用distributable元素)ServletContext的作用范围就只有单个虚拟机而不是整个Web Application

7.servlet中的幂等请求
get,head,put是被认为幂等请求,也就是多个完全相同的请求过来时只当做一个请求来处理,非幂等的请求则是当做多个请求来处理。
即get从服务器获得数据,不会更新数据,post会更新数据库信息。这个就是为什么在用get方式请求服务器的时候会带上一个无效的时间参数,来让服务器来将最新的数据返回。
8.getServerPort(),getLocalPort(),getRemotePort()区别

8.1 getRemotePort() 获得远程客户端端口
8.2 getServerPort() 获得请求原来发送的端口
8.3 getLocalPort() 获得请求最后发送的端口
因为servlet会处理多个请求,每个请求会为每个线程找一个不同的端口

1. response 对象

一般用于向客户端返回请求。设置需要返回内容类型
一个典型的读取jar包的输出返回

package com.xzm.servlet;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ContentTypeServlet extends HttpServlet {

/**
*
*/
private static final long serialVersionUID = 1L;

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
//设置定返回的对象类型,告诉浏览器你要返回的数据类型
resp.setContentType(“application/jar”);

//根据系统级的参数获取读取文件资源的方式
ServletContext ctxContext = getServletContext();
// getResourceAsStream()方法需要以/开头,这个表示web应用的根路径:webApp/XXweb/bookCode.jar 与WEB-INF同级
InputStream is = ctxContext.getResourceAsStream(“/bookCode.jar”);

int read = 0;
byte[] buffer = new byte[1024];

OutputStream os = resp.getOutputStream();
while((read = is.read(buffer))!=-1)
{
os.write(buffer);
}

is.close();
os.close();
}

}

常见的MIME类型:

text/html
application/pdf
video/quicktime
application/java
application/jpeg
application/jar
application/octet-stream
application/x-zip

response的输出返回有两种
一种是字节响应,另一种是字符响应

字节响应:
OutputStream os = resp.getOutputStream();

字符响应:
PrintWriter pWriter = resp.getWriter();
response的其他常用方法

//如果响应中已经有这个值就替换,否则就新增
resp.addHeader(“gg”, “ff”);

//覆盖原有的值
resp.setHeader(“gg”, “ff”);

//用提供的值替换原有的值,或者在响应中添加一个新的值
resp.setIntHeader(“gg”, 43);

2 重定向:

重定向设置有两种方式 :绝对路径重定向、相对路径重定向

绝对路径重定向:
resp.sendRedirect(“http://www.sina.com.cn”);

相对路径重定向:
又可以分为两种:前面有斜杠、前面无斜杠

一个客户请求:
http://www.wickeddly.com/myApp/cool/bar.do

在跳转到这个请求中后,无斜杠进行重定向:
sendRedirect(“foo/stuff.html”);

结果容器的解析后会变成一个完整的路径:
http://www.wickeddly.com/myApp/cool/foo/stuff.html

若是加斜杠的重定向
sendRedirect(“/foo/stuff.html”);

结果容器的解析后会变成一个完整的路径:
http://www.wickeddly.com/foo/stuff.html

myApp/cool/ 消失了

不要在提交响应之后再次调用sendRedirect方法
3 请求分配

重定向是让客户来完成工作,请求分配要求服务器上的XX来完成工作,也就是重定向是再次将路径返回给浏览器,浏览器再次请求服务器的过程,即完成了跳转。所以它的请求路径会发生变化.而请求分配给浏览器的访问路径不会发生变化 。两次请求!但是客户端的URL不会变动

请求分配的调用方式

RequestDispatcher view = req.getRequestDispatcher(“result.jsp”);
view.forward(req, resp);
http://127.0.0.1:8080/lottery/login.do 请求过来 通过
lottery:是应用名称
1)第一种形式:
RequestDispatcher view = req.getRequestDispatcher(“/lottery/common/error.jsp”);
最后客户端请求的地址是: /lottery/lottery/common/error.jsp
2)第二种形式:
RequestDispatcher view = req.getRequestDispatcher(“/common/error.jsp”);
最后客户端请求的地址是: /lottery/common/error.jsp
3)第三种形式:
RequestDispatcher view = req.getRequestDispatcher(“common/error.jsp”);
最后客户端请求的地址是: /lottery/common/error.jsp

通过上面的案例我们可以知道
通过foward的方式 加不加 /没什么区别

sendRedirect和foward 之间区别和联系
sendRedirect修改的是http的header,直接制定浏览器进行重定向。所以这个制定非本引用的资源!
若是加/的话,那么就是从域名开始拼接请求。不加/的话就是在请求过来的路径上加后缀,实力可见上面!
foward是在服务端做得重定向,应用内部的跳转,一个servlet跳转到另一个servlet!
就是评级 contenxtpath + 在后端的设置。加不加/无所谓。就是上面的第二,三种形式。
请求中的路径设置同重定向中的绝对和相对设置方式

4. 初始化参数

servletConfig:

获取方式:getServletConfig()

容器初始化一个servlet时,会为这个servlet建立一个唯一的servletConfig

容器从web.xml中读取servlet初始化参数,并把这些参数交给servletConfig,servletConfig接着传递给servlet的init方法

不要在构造函数中获取初始化参数,一个servlet只有在执行init方法后才算一个完整的servlet。如果必要的话,一般需要覆盖无参的init方法

生命周期:

1.容器读取配置文件
2.new一个servletConfig
3.servletConfig根据配置文件生成一个MAP的键值对
4.new一个servletConfig.class的实例
5.容器再次调用init()方法

JSP不能访问每个servletConfig中的初始化设置

配置:在servlet内部配置

ServletContext:上下文初始化参数

获取方式:getServletContext()

配置:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:bme.service.xml
/WEB-INF/conf/global.datasource.xml
/WEB-INF/conf/*.service.xml /WEB-INF/conf/*.web.xml
classpath:org/codehaus/xfire/spring/xfire.xml
classpath:iManager/spring/repository_service.xml
</param-value>
</context-param>

servletContext与servletConfig之间的区别

1. 部署文件不同
一个是配置在web-app目录下
一个是配置在每个servlet下

2. 获取方式不同
getServletConfig(),getServletContext

3. 应用范围不同
getServletConfig只应用于单独对立的一个servlet。

getServletContext应用于所有的JSP和所有的servlet。
4. 监听器

使用场景:在某类时间出发之前或之后处理事件例如想监听一个上下文初始化事件,这样能获得一些上下文参数,并在应用客户端之前运行一些代码

如果实现上下文的监听器,则需要实现ServletContextListener

详细代码如下所表示:
package com.xzm.listen;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class ContextListener implements ServletContextListener
{

public void contextDestroyed(ServletContextEvent arg0)
{
ServletContext sct = arg0.getServletContext();
sct.getInitParameter(“ahah”);
System.out.println(“离开上下文监听器了…….”);
}

public void contextInitialized(ServletContextEvent arg0)
{

System.out.println(“进入上下文监听器了……”);
}

}

1. 不是所有的类都需要实现序列化接口,在同一个JVM中,且未写入存储设备中,不需要实现序列化接口。

2. 了解各种常见的监听器

3. 三种存储空间的比较

应用上下文 请求 会话

生命周期 整个应用 单个请求(线程安全) 会话连接(非线程安全)

可访问性 servlet,jsp, 持有这个会话的所有servlet 该请求相关的对象及相关监听器
lisntener etc jsp

适用于 整个应用共享的资源 与客户端会话有关的资源和数据 将模型数据从控制器传递到视图
DB连接,JNDI,
email

4. 上下文中值的存储设置需要设置为线程安全,对关键代码做同步,而不需要对所有方法做同步

例如:
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
PrintWriter out = resp.getWriter();
out.println(“test content attributes<br>”);

synchronized(getServletContext())
{
getServletContext().setAttribute(“foo”, “22”);
getServletContext().setAttribute(“bar”, “42”);

}

out.println(getServletContext().getAttribute(“foo”));
out.println(getServletContext().getAttribute(“bar”));

}
5. 会话中保持线程安全。同理,在获取会话的时候进行同步加锁

HttpSession session = req.getSession();
synchronized (session)
{
session.setAttribute(“foo”, “df”);
session.setAttribute(“bar”, “df”);
}

out.println(session.getAttribute(“foo”));
out.println(session.getAttribute(“bar”));
6. 若是多个线程在运行某段servlet代码,那么该servlet的实例变量也不是线程安全的,所以尽量不要在servlet中定义实例变量。
servlet只有一个实例,但是可以有多个线程 。若是为了解决多个线程访问同一个值的话,那么可以考虑设置在某一级别的作用域中

7. 不同获得dispatch的方式
RequestDispatcher dispatcher = req.getRequestDispatcher(“result.jsp”);
— 这种方式获得的对象可以针对相对路径进行转发

RequestDispatcher dispatcher2 = getServletContext().getRequestDispatcher(“/result.jsp”);
— 这种方式或的对象不能针对当前相对路径进行转发,需要设置斜杠来跳转 /

8. 如果已经提交了响应,那么就不能进行转发操作,否着会报无效状态异常

9. 会话 session
1.HttpSession session = req.getSession();
2.HttpSession session2 = req.getSession(true);

两者完全相同,若是会话不存在的话,创建一个新的会话。存在的话则使用旧的会话

3.HttpSession session3 = req.getSession(false);
如是已经存在会话的话,则返回会话对象,若是不存在的话,那么返回null

为了保持同一个session的话,是通过cookie来实现的,若是客户端屏蔽了cookie的话,那我们可以使用URL重写的方式来保持session的统一
URL重写的方式有两种:

1. 不加URL重写
out.println(“<html><body>”);
out.println(“<a href=\”Listener.do\”>click me</a>”);
out.println(“</body></html>”);

这种方式的跳转不会在禁止cookie的情况下会丢失session,返回的地址是:
http://localhost:8080/JspStu/Listener.do

2. 加上URL重写
out.println(“<html><body>”);
out.println(“<a href=\””+resp.encodeURL(“Listener.do”)+”\”>click me</a>”);
out.println(“</body></html>”);

这种方式在跳转时,在禁止cookei的情况下亦不会丢失session,返回的地址是:
http://localhost:8080/JspStu/Listener.do;jsessionid=8391FEED24807566F8E10A127BA1BC80

使用URL重写就必须保证页面时动态生成的

1. 会话的销毁
1.1 设置会话的超时时间
<session-config>
<session-timeout>30</session-timeout>
</session-config>
单位为分

1.2 在代码进行设置程序的超时时间

session.setMaxInactiveInterval(20*60); 单位是秒
2. 若一个session已经销毁了,结果就无法调用其中的属性,否则会报无效状态异常

情况一:
resp.setContentType(“html/text”);
PrintWriter pWriter = resp.getWriter();
HttpSession session = req.getSession();

session.setAttribute(“foo”, “42”);
session.setMaxInactiveInterval(0);
if (session.isNew())
{
pWriter.println(“this is a new session!”);
}
else
{
pWriter.println(“welcome back!”);
}

pWriter.println(“Foo” + session.getAttribute(“foo”));

情况二:

resp.setContentType(“html/text”);
PrintWriter pWriter = resp.getWriter();
HttpSession session = req.getSession();

session.setAttribute(“foo”, “42”);
session.setAttribute(“bar”, “420”);
session.invalidate();
String foo = (String)session.getAttribute(“foo”);
pWriter.println(“Foo”+foo);

3. 会话的迁移

上下文、servletConfig、session ,在从一个JVN迁移到另一个JVM时候,上下文和servletConfig会进行复制,session会迁移。及在分布式系统中,只会保持一份session

即session从一个VM钝化,从另一个VM激活。

4. jsp的编译过程

myjsp.jsp –> myjso_jsp.java –> myjso_jsp.class –> myjsp_jsp (servlet)

4.1 scriptlet代码:

<html><body>
<% out.printLn(Count.getCount());%>
</body></html>

4.2 表达式代码:

<html><body>
<%= Count.getCount()%>
</body></html>

4.3 第三种方式
<html><body>
<%! int a = 1 >
<%= Count.getCount()%>
</body></html>

4.1. 4.2 两者进行比较发现:表达式没有out对象和分号

表达式代码中Count.getCount()会被转化为out.printLn(Count.getCount());

4.1 4.2 声明的变量都是在service方法内,4.3方法是在service方法之外。

<body>
This is my JSP page. <br>
<%! int b = 6; %>
<% int a = 5; %>
<%=a %>
<%=b %>

</body>

编译之后为:
public final class Count_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent {

int b = 6;

。。。。。。

public void _jspService(HttpServletRequest request, HttpServletResponse response) —对应到servlet中的service方法
throws java.io.IOException, ServletException {

…….

int a = 5;

…..
out.print(a );
out.write(“\r\n”);
out.write(” “);
out.print(b );

}

作者: inter12

在这苦短的人生中,追求点自己的简单快乐

发表评论

电子邮件地址不会被公开。 必填项已用*标注