对forward的行为的汇总:
1.控制的转移完全在服务器上进行。不涉及任何网络数据流。
2.用户不会看到目的JSP页面的地址,而且还可以将页面放在WEB-INF中,防止用户不经过建立数据的servlet直接访问页面。如果JSP页面只在由servlet生成的数据上下文中才有意义,则更应该这样做。
对sendRedirect的汇总:
1.控制的转移通过向客户发送302状态码和Location响应报头来完成。转移需要另外的网络往返。
2.用户能够看到目的页面的地址,并可以记下来,独立地访问。如果将JSP设计为数据缺失时使用默认值,这种方式比较适用。
基于request的数据共享
ValueObject value = new ValueObject();
request.setAttribute("key", value);
RequestDispatcher dispatcher = request.getRequestDispatcher(somepath);
dispatcher.forward(request, response);
基于session的数据共享
ValueObject value = new ValueObject();
HttpSession session = request.getSession();
session.setAttribute("key", value);
RequestDispatcher dispatcher = request.getRequestDispatcher(somepath);
dispatcher.forward(request, response);
基于application的数据共享
synchronized(this){
ValueObject value = new ValueObject();
getServletContext().setAttribute("key", value);
RequestDispatcher dispatcher = request.getRequestDispatcher(somepath);
dispatcher.forward(request, response);
}
Servlet
在web.xml中
在servlet文件中
out.println(getServletConfig().getInitParameter("adminEmail"));
每个servlet 都继承一个getServletConfig()方法
上面会输出[email protected]
一旦生成ServletConfig引用,你能使用getInitParameter()方法。记住不能在构造体内调用。
容器从DD文件中读取Servlet init parameters,然后传给ServletConfig对象,再把ServletConfig传递到Servlet中的init()方法去。
1、String getInitParameter(String)
2、Enumeration getInitParameterNames()
3、ServletContext getServletContext()
4、String getServletName()
在web.xml中
在servlet文件中
out.println(getServletContext().getInitParameter("adminEmail"));
ServletContext 是每个web-app一个
ServletConfig 是每个servlet一个
在整个web app中有且只有一个ServletContext,web app的所有部份都共享它。
但一个app 中的每个servlet都有自己的ServletConfig。
当web app部署时容器生成一个ServletContext,同时使这个ServletContext对这个web app里的每个Servlet和JSP都可用。
可以通过两种方法获取ServletContext
getServletConfig().getServletContext().getInitParameter();
和
this.getServletContext().getInitParameter();
<
contextInitialized(ServletContextEvent);
contextDestroyed(ServletContextEvent);
当ServletContext初始化(即app被部署)时引起注意:
1、从ServletContext中获取context init paramete。
2、使用init parameter 去查找名字创建数据库连接。
3、把数据库连接当作属性来存储,以致整个web app都可以访问到。
当ServletContext被破坏(即app被部署)时引起注意:
1、关闭数据库连接
import javax.servlet.*;
public class MyServletContextListener implements ServletContextListener{
public void contextInitialized(ServletContextEvent event){
//code to initialize the database connection
//and store it as a context attribute
}
public void contextDestroyed(ServletContextEvent event){
//code to close the database connection
}
}
这个例子中,把字符串类型的init parameter 变为一个对象--Dog对象。
listener的工作是为Dog的breed()方法获取context init parameter。
⑴、listener向ServletContextEvent对象请求一个引用到app ServletContext。
ServletContext sc = event.getServletContext();
⑵、listener使用这个引用来获取context init parameter "breed",它是表示dog breed的字符串。
String dogBreed = sc.getInitParameter("breed");
⑶、listener使用此字符串来构造一个Dog对象。
Dog dog = new Dog(dogBreed);
⑷、listener用之前的引用将Dog对象保存在ServletContext属性中。
sc.setAttribute("dog", dog);
⑸、测试的Servlet从ServletContext中获取Dog对象,并调用Dog类的getBreed()方法。
构建和使用context listener
1、创建listener类,实现ServletContextListener接口 (实现接口中的两个方法)。
2、将这个类放置于WEB-INF/classes目录中 (这并不是唯一的地方)。
3、在部署描述器web.xml中增加一个
import javax.servlet.*;
public class MyServletContextListener implements ServletContextListener{
public void contextInitialized(ServletContextEvent event){
ServletContext sc = event.getServletContext();
String dogBreed = sc.getInitParameter();
Dog dog = new Dog(dogBreed);
sc.setAttribute("dog", dog);
}
public void contextDestroyed(ServletContextEvent event){
//do nothing
}
}
public class Dog{
private String breed;
public Dog(String breed){
this.breed = breed;
}
public String getBreed(){
return breed;
}
}
public class ListenerTester extends HttpServlet{
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("test servlet listener");
out.println("
");
Dog dog = (Dog)getServletContext().getAttribute("dog");
out.println("The dog's breed is "+dog.getBreed());
}
}
HttpSessionAttributeListener 知道session中任何一种attribute 何时被增加,删除或代替。
HttpSessionBuildingListener 使得session中attribute本身能够知道自己何时被增加或删除。
Context scope 不是线程安全的。
一个app中的每个人都能够访问context attribute,就是说多servlets。多servlets意味着多线程。因为请求是并发处理的,每个发生在不同的线程,不管请求来自相同还是不同的servlet。
保护context attribute的典型方法是对context 对象进行同步(synchronize)。如果之前的人锁住了context对象,则能保证一个时刻只有一个线程能够对context attribute进行getter、setter操作。
synchronized(getServletContext()){
}
Session attribute也不是线程安全的。
synchronized(request.getSession()){
}
只有request attribute和local variables是线程安全的。
You can get a RequestDispatcher in two ways: from the request or from the context.
RequestDispatcher view = request.getRequestDispatcher("result.jsp");
and
RequestDispatcher view = getServletContext().getRequestDispatcher("/result.jsp");
不能是相对于当前资源的路径
So, don't be fooled if you see questions that forward a request after a response is sent. The Container will throw an illegalStateException.
The idea is simple: on the client's first request, the Container generates a unique session ID and gives it back to the client with the response. The Container sees the ID, finds the matching session, and associates the session with the request.
request.getSession(false) false 表示返回一个已经存在的session,或如果没有session则是null。
A client with cookies disabled will ignore "Set-Cookie" response headers.
如果用户禁用cookie,可以用URL回写技术。
out.println("Click me");
重定向时用回写:response.encodeRedirectURL("test.do");
Filter 能做的事情
Request:
perform security checks
reformat request headers or bodies
audit or log requests
Response:
compress the response stream
append or alter the response stream
create a different response altogether
url-pattern:必须以/开头
如:
在html的form表单中,则是