|
Servlet2.4:是sun公司提出的一个标准,作为容器提供商和我们开发人员必须按照这个标准来开发容器和
开发web应用;开发人员实现Servlet的接口,service方法是由容器调用的,并且会传进来request和
WEB应用的目录结构;
servlet中的方法由所处的容器来调用;
<form method="post" action="helloservlet">
</form>
Http请求:包括请求头和请求体
Get请求:浏览器提交的数据是放在请求头部的;
Post请求:浏览器提交的数据是放在请求体部的;
Web application server:
Tomcat:
opt/jakarta_tomcat5.0.28
一、tomcat和servlet介绍
Tomcat的目录结构
1) bin:主要存放tomcat的一些可执行文件,比如:startup.bat,shutdown.sh;
2) common:主要用来存放tomcat以及所有的web应用都可以用的一些类或则.jar文件;
3) conf:其中包含着Tomcat的配置文件,主要是server.xml、web.xml和tomcat-users.xml等;
conf/server.xml:修改Tomcat的端口
conf/web.xml:设置默认主页
conf/tomcat-users.xml:添加Tomcat的Admin和Manager用户
conf/Catalina/../新建xml文件,指定docBase,可以设定Tomcat应用的
路径,默认是在Tomcat/webapps目录
4) logs:包含着Tomcat的日志文件以及应用的日志文件;
5) server:存放只有tomcat能使用的类或者jar文件以及tomcat自带的web应用,包含着运行Catalina
容器所需要的文件以及类库;
6) shared:存放所有的web应用共享的.class和.jar,但是tomcat不能使用;
7) temp:用来存放临时文件;
8) webapps:存放我们开发的web应用;
9) work:通过jsp生成的servlet类存放的目录;
-------------------------------------------------------------------------------------------
在windows下配置tomcat:
CATALINA_HOME=
-------------------------------------------------------------------------------------------
home目录下:
1.打开控制台;
2.vi .bashrc
3.export JAVAHOME=/opt/java/jdk/jdk1.5.0_06
export CATALINA_HOME=/opt/jakarta-tomcat-5.0.28
4.保存配置文件;
5.source .bashrc;
-------------------------------------------------------------------------------------------
启动tomcat
1、在命令行窗口启动;需要配置环境变量;JAVA_HOME(必须),CATALINA_HOME(必须),
PATH(可选)
执行%CARALINA_HOME%\bin下startup.bat启动tomcat,shutdown.bat关闭tomcat;
2、在eclipse中启动;无须配置系统环境变量;通过myeclipse插件集成tomcat;
-------------------------------------------------------------------------------------------
WEB应用的目录结构:
Servlet
--WEB-INF
--classes存放开发的java类,比如说是servlet类
--lib 存放第三方的jar包,比如说ojdbc14.jar
--web.xml 对servlet进行描述
--.htm .html .jsp
就编写好的上述程序放入%CATALINA-HOME\webapps\中;
url-pattern
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
----------------------------------------------------------------------------------------------------------------------------------
Http协议:是应用层的协议,他是无状态的。它是架在tcp/ip传输层协议之上的,对传输数据的格式做
了一个定义。
-------------------------------------------------------------------------------------------
CGI和Servlet的优缺点:
CGI程序可以有多种语言编写,但是服务器端处理请求使用进程,消耗服务器端资源;
Servlet只能由java编写,服务器端处理请求使用线程,移植性好;
-------------------------------------------------------------------------------------------
什么是Servlet?
JEE规范的一部份,是用java语言编写的服务器端程序,
用于创建动态web页面,不依赖于具体的协议,必须运行于web容器中。
-------------------------------------------------------------------------------------------
在tomcat根目录下的conf目录下修改:
配置tomcat-users.xml
<?xml version='1.0' encoding='utf-8'?>
<tomcat-users>
<role rolename="manager"/>
<role rolename="admin"/>
<user username="tomcat" password="tomcat" roles="admin,manager"/>
</tomcat-users>
-------------------------------------------------------------------------------------------
配置server.xml
<Connector port="8080"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" redirectPort="8443" acceptCount="100"
debug="0" connectionTimeout="20000"
disableUploadTimeout="true" />
-------------------------------------------------------------------------------------------
在CATALINA/localhost下面配置一个新的文件:admin.xml
其中path里面填写的是你的工程名字,docBase里面填写的是WEB-INF的路径;
<Context path="/admin" docBase="/home/briup/works/Servlet/WebRoot"
debug="0" privileged="true">
<Logger className="org.apache.catalina.logger.FileLogger"
prefix="localhost_admin_log." suffix=".txt"
timestamp="true"/>
</Context>
-------------------------------------------------------------------------------------------
本来面目:
<url-pattern>/hello</url-pattern>
访问时在地址栏只能写
http://127.0.0.1:8080/Servlet/hello
为了加强灵活性和易用性,方法如下:
后通配:
<url-pattern>/hello/*</url-pattern>
访问时在地址栏里写
http://127.0.0.1:8080/Servlet/hello/asdasd/asdasd/asdasd
都是可以的;
前统配:
<url-pattern>*.hello</url-pattern>
http://127.0.0.1:8080/Servlet/*.hello
http://127.0.0.1:8080/Servlet/a.hello
http://127.0.0.1:8080/Servlet/abc/a.hello
都是可以的;
-------------------------------------------------------------------------------------------
HttpServlet继承自GenericServlet,其中的service方法自动实现;
GenericServlet的调用方法:
容器
——————>service(ServletRequest req,ServletResponse res)
————>service(HttpServletRequest req,HttpServletResponse res)
——METHOD="GET"——>doGet(HttpServletRequest req,HttpServletResponse res)
——METHOD="POST"——>doPost(HttpServletRequest req,HttpServletResponse res)
-------------------------------------------------------------------------------------------
表单的处理:
<FROM METHOD="POST" ACTION="servlet/FormServlet">
-------------------------------------------------------------------------------------------
获取客户端提交的信息:
1)HttpServletRequest.getParameterNames():获取所有表单信息
2)HttpServletRequest.getParameter(key):获取指定key的信息
3)HttpServletRequest.getParameterValues(key):表单项有多个值,用此方法
客户端向服务器端提交信息
1)使用表单,即<form>
2)在URL后追加 ?name=value&name=value
获取HTTP请求的头部信息:
1)HttpServletRequest.getHeaderNames()
2)HttpServletRequest.getHeader(...)
如referer可以取到上一个网页的URL
localhost:8888/servletjd0710/ch2/RequestServlet?name=briup&age=10
request.getContextPath():/servletjd0710
request.getQueryString():name=briup&age=10
request.getRequestURI():/servletjd0710/ch2/RequestServlet
request.getRequestURL():http://localhost:8888/servletjd0710/ch2/
request.getServletPath():/ch2/RequestServlet
二、servlet的生命周期
1)由容器装载并实例化,产生一个实例
2)由容器调用init()方法,不需要考虑多线程
只被调用一次
init(ServletConfig config)先被调用
nit()后被调用
设置初始化参数:
1, 全局的
<context-param>
<param-name>age</param-name>
<param-value>20</param-value>
</context-param>
通过ServeltConfig.getServletContext().getInitParameter(...)取
2,局部的
<servlet>
<servlet-name>helloservlet</servlet-name>
<servlet-class>com.briup.ch3.HelloServlet</servlet-class>
<init-param>
<param-name>name</param-name>
<param-value>zhangsan</param-value>
</init-param>
</servlet>
通过ServletConfig.getInitParameter(...)取
3)根据用户的每一次请求,调用一次服务方法doGet/doPost等,需要考虑多线程
service(ServletRequest,ServletResponse)
service(HttpServletRequest,HttpServletResponse)
doGet()/doPost()
多线程处理
1)implements SingleThreadModel
每个请求创建一个Servlet实例为其服务,性能低,不建议使用
2)建议在servlet类用不要使用实例变量,
如果用,使用synchornized进行同步
4)由容器调用destroy()方法,不需要考虑多线程
只被调用一次
clean shutdown(无损关机)
-------------------------------------------------------------------------------------------
容器实例化servlet的顺序:
1.当load-on-startup为负数的时候,servlet会在第一次访问的时候被实例化,默认情况下load-on-startup为-1;
2.当load-on-startup为正数的时候,在tomcat装载web应用的时候servlet就会被实例化;
3.load-on-startup为0的时候,最晚被实例化;
4.load-on-startup>0的时候,值越小就越早被实例化;
-------------------------------------------------------------------------------------------
GenericServlet:重载有参的init()方法,调用无参的init()方法.无参的init()方法用于初始化程序.
-------------------------------------------------------------------------------------------
request范围:
-------------------------------------------------------------------------------------------
三、资源跳转的方式
(内部跳转:forward和include,外部跳转:sendRedirect)
1)forward
forward后的响应内容由所请求的资源给出
RequestDispatcher rd=request.getRequestDispatcher("SuccessServlet");
request.setAttribute("userinfo", "new User()");
rd.forward(request, response);
2)include
inclue后的响应内容由其本身给出
out.println("<html><body>");
RequestDispatcher rd = request.getRequestDispatcher("/ch04/header");
rd.include(request,response);
out.println("</body></html>");
forward和include的相同点:
绝对路径中/都是web应用
服务器内跳转,客户端地址栏无变化
都是同一个请求
3) sendRedirect
客户端地址栏发生变化
两次请求,request范围内设置的所有属性将失效
response.sendRedirect("ShowInfo");
/指代 响应内容 地址栏 请求 跨应用
forward
web应用 请求资源 不变 一次 不能
include
web应用 本身 不变 一次 不能
sendRedirect
服务器 请求资源 变化 两次 能
web应用: http://localhost:8080/hello
服务器: http://localhost:8080
<form action="/...">,<a href="/...">:"/"指代服务器
注:能用forward方式,就不要用sendRedirect
1)从性能
2)从对服务器内部资源的保护(地址栏内能否显示服务器资源URL)
考虑
保护服务器资源
1)使用Filter对请求进行过滤
2)把要保护的资源方到WEB-INF下,客户端浏览器不能直接访问该目录下
的资源,我们可以通过Servlet等访问
设置属性的四个范围:
范围 对应类 Jsp内建对象
javax.servlet.ServletContext application
应用级别 针对整个web应用
javax.servlet.http.HttpSession session
会话级别 针对一次会话
javax.servlet.http.HttpServletRequest request
请求级别 针对一次请求
javax.servlet.jsp.PageContext page
页面级别 针对一个页面
注:一个application可以跨越多个session,一个session可以跨越多个request,
一个request可以跨越多个page;
实际项目开发中,从性能、占用资源角度考虑,优先使用小级别的;
获取RequestDispatcher
1)HttpServletRequest.getRequestDispatcher(...):相对/绝对路径
2)ServletContext.getRequestDispatcher(...):绝对路径
注:这里的相对是绝对,/表示web应用(如http://localhost:8080/hello)
3)ServletContext.getNamedDispatcher(...):根据servlet的名字获取
------------------------------------------------------------------------------------------
forward之前不能pw.flush();
------------------------------------------------------------------------------------------
外部跳转:让浏览器重新发送一个新的请求,跳转前后不是同一个请求;访问前后路径不同;
------------------------------------------------------------------------------------------
总结:
forward:内部跳转或则是服务器内部重定向;
servlet1-------forward-----servlet2
servlet1和servlet2中的request对象是同一个。
sendRedirect:外部跳转或则服务器外部重定向;
servlet1-------sendredirect-----servlet2
servlet1和servlet2中的request对象不是同一个。
作外部跳转调用response的sendRedirect方法,这个方法中传入的路径可以是相对的,也可以是绝对的;
相对的跟forward相同;
绝对的:应用路径+servlet url-pattern(这点和内部跳转是不同的);
------------------------------------------------------------------------------------------
四、在tomcat中配置数据源
1)Admin登录,找到项目
2)创建Data Source
JNDI Name: jdbc/oracle
URL: jdbc:oracle:thin:@192.168.1.200:1521:briupdb
Driver: oracle.jdbc.driver.OracleDriver
User: briup
Password: briup
3)web.xml中配置资源引用(可选,新版本的tomcat不需要配置)
<resource-ref>
<description>
Oracle Datasource example
</description>
<res-ref-name>jdbc/oracle</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
4)Context ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/oracle");
注:配置数据源之后,在Tomcat/config/Catalina/..目录下会新建一个xml文件,
里面存放数据源相关的信息
五、持久化状态:Cookie,Session
HTTP协议是无状态的,为了保存会话状态,我们有两种解决方案:
1、Cookie,把会话状态信息保存在客户端
2、Session,把会话状态信息保存在服务器端
Cookie:保存一些键/值对,到客户端浏览器
name:briup
password:briup
使用Cookie:
1)创建Cookie
Cookie cookie = new Cookie("name","value");
2)将Cookie加到客户端浏览器
HttpServletResponse.addCookie(cookie);
3)在服务器端取出Cookie(返回Cookie[ ])
HttpServletRequest.getCookies();
Cookie.getName();
Cookie.getValue();
会话Cookie:只在当前会话起作用的Cookie
持久Cookie:保存在客户本地一段时间的Cookie
设置Cookie的时长:Cookie.setMaxAge(int second),单位秒
设置Cookie的有效路径:Cookie.setPath(...)
Cookie:由服务器创建,但是存放在客户端;
Cookie cookie=new Cookie(name,value);
cookie.setMaxAge(timeout);
当timeout<0时,意味着这个cookie只要浏览器关闭就会消失;
当timeout=n(n>0)时,意味着cookie将会在客户端被保存n秒;
当timeout=0时,意味着这个cookie将会被删除;
name相同的cookie会被覆盖.
response.addCookie(cookie);
服务器端获得客户端传过来的cookie:Cookie[] cookies=request.getCookies();
Session:
获取Session的方法:
HttpServletRequest.getSession()<==>HttpServletRequest.getSession(true)
如果客户和服务器已经建立起会话,直接使用已有的Session对象,
如果没有建立,就新建一个Session对象
HttpServletRequest.getSession(false);
设置属性:HttpSession.setAttribute("name",Object);
获取属性:HttpSession.getAttribute("name");
删除属性:HttpSession.removeAttribute("name");
使用Session来保存会话信息,在客户端也要留下一个标识,一般用JSESSION表示
在用户禁用Cookie时使用Session方式在服务器端维持会话状态,在客户端要留一个Session的id号,
优先使用Cookie的JSESSIONID存放,如果禁用了Cookie,URL重写的Session id号会被追加到
浏览器地址中URL的后面,用jsessionid表示
(http://localhost:8888/servlet/ch5/urlcounter;jsessionid=9FFA9CCB7D86134E0256E94D05E6DC44)
重写:String encodedURL = response.encodeURL("/servletjd0710/ch05/UrlBasedCounterServlet");
Session什么时候失效?
1:程序中调用HttpSession.invalidate()方法
2:Session过期,在Session的最大有效时间以外
3:关闭应用服务器
设置Session的有效时间:
1:HttpSession.setMaxInactiveIntervale(int second) 单位秒
2:在web.xml中进行配置
<session-conf>
<session-timeout>...</session-timeout><!-- 单位分钟 -->
</session-conf>
注意:当程序中和web.xml中都设置了Session的有效时间时,以程序中的设置为准
复习:
1.创建servlet对象(通过load-on-startup来决定在什么时候被创建);
2.当servlet对象被创建成功以后,容器马上会调用它的有参的init方法---init只被调用一次;
3.服务客户端请求,客户端发起一个请求,容器就会调用servlet的service方法,并且传入ServletRequest,
ServletResponse对象;------service方法可以被调用多次;
4.当容器关闭或则应用被卸载的时候,servlet对象会被销毁,在销毁之前容器会调用destroy方法,
----destroy只被调用一次;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Datasource中存放的是collection;可以通过new来新建一个,也可以在目录服务器中通过JNDI获取;
跳转:内部跳转和外部跳转;最大区别:请求是否是同一个;
cookie&session:记录用户相关状态;最大区别:存放的位置不同;session可以存放对象.cookie不可以;
JSESSIONID一般是通过cookie写入客户端,如果关闭cookie则不能使用session;所以还有另外的方法;
URL重写:
<a href=state/modifyRelease;jsessionid=XXXXXXXX>modifyRelease</a>
------------------------------------------------------------------------------------------
req.getSession()
从request对象中获取jsessionid,如果根据这个jsessionid找不到一个对应的session
对象,则创建一个新的session对象返回,如果能找到则返回找到的session对象;
req.getSession(boolean create)
如果create为true,等价于req.getSession();
如果create为false,根据request对象传过来的jsessionId查找对应的session对象,如果能找到则返回
找不到则返回null;
六、request、session、application
request生命周期:生于容器接收到请求,死于servlet产生响应;
session生命周期公司
创建:客户端访问一个servlet,在servlet中调用了req.getSession方法;
销毁:1.关闭浏览器进程;
2.session过期;(在web.xml中指定<session-timeout>10</session-timeout>10钟后过期)
3.调用session.invalidate()方法;
不建议将大量数据放在内存中,这样会比较消耗服务器内存的;
requestScope=====>HttpServletRequest对象 (Scope:作用范围)
request.setAttribute(name,value)
Object value=request.getAttribute(name);
request.removeAttribute(name)
sessionScope=====>HttpSession对象
session.setAttribute(name,value)
Object value=session.getAttribute(name)
session.removeAttribute(name)
applicationScope=====>ServletContext对象
对于一个应用来说ServletContext对象是唯一的,存放所有用户登陆的共用信息;
创建:应用装载的时候
销毁:应用卸载的时候
sc.setAttribute(name,value)
Object value=sc.getAttribute(name)
sc.removeAttribute(name)
七、Filter:过滤器
对服务器上的特定资源采取措施,进行限制
Filter的应用:延迟登录、编码转换、审计......
Filter的使用步骤:
1)写Filter类
implements javax.servlet.Filter接口
重写Filter接口中的方法init(FilterConfig),
doFilter(ServletRequest,ServletResponse,FilterChain) , destroy()
2)在web.xml中进行配置
<filter>
<filter-name> 自己取,但要和<filter-mapping>中的对应 <filter-name>
<filter-class> Filter类的全限定名 </filter-class>
<init-param>
<param-name>...</param-name>
<param-value>...</param-value>
<init-param>
</filter>
在程序中通过FilterConfig.getInitParameter("name")取
<filter-mapping>
<filter-name> 和<filter>中的对应 </filter-name>
<url-pattern> Filter所限制访问的资源路径 </url-pattern>
</filter-mapping>
比如我们将<url-pattern>设为/ch5/*,那么我们在浏览器中访问/ch5下的
资源时Filter就会自动被调用
Filter的生命周期:
1)init(FilterConfig)
由容器调用,并且只调用一次
2)doFilter(ServletRequest,ServletResponse,FilterChain)
访问限定资源时,被调用,会被调用多次,注意考虑多线程问题,
处理方式和Servlet中的一样
3)destroy()
由容器调用,并且只调用一次
FilterChain.doFilter(ServletRequest,ServletResponse):可以认为是处理请求和
响应的分界限,在chain.doFilter(...)之前处理请求,在chain.doFilter(...)之后
处理响应
注意:一旦写了Filter一定要在Filter.doFilter(...)中调用FilterChain.doFilter()
方法,将请求交由其他资源继续处理
编码转换:
request.setCharacterEncoding("UTF-8");
chain.doFilter(request, response);
response.setCharacterEncoding("UTF-8");
过滤的url: /*
相同的资源可以被多个Filter过滤,Filter的执行顺序取决于web.xml中配置的
<filter-mapping>的顺序
八、监听器
监听器,对特定事件所采取的控制
常见事件:应用服务器的启动/关闭,会话的创建/删除,请求的创建/删除,属性的增加、替换、删
除等
Listener分类
应用级别:
ServletContextListener:
void contextDestroyed(ServletContextEvent sce):监听应用服务器的关闭
void contextInitialized(ServletContextEvent sce): 监听应用服务器的启动
ServletContextAttributeListener:
void attributeAdded(ServletContextAttributeEvent scab):
监听应用级别属性的增加,即ServletContext.setAttribute("user","briup")
void attributeRemoved(ServletContextAttributeEvent scab):
监听应用级别属性的删除,即ServletContext.removeAttribute(...)
void attributeReplaced(ServletContextAttributeEvent scab):
监听应用级别属性的替换,即使ServletContext.setAttribute("user","ibm")
会话级别:
HttpSessionListener
void sessionCreated(HttpSessionEvent se):监听会话的创建
如,HttpServletRequest.getSession()
void sessionDestroyed(HttpSessionEvent se):监听会话的删除
如,HttpSession.invalidate()
HttpSessionAttributeListener
void attributeAdded(HttpSessionBindingEvent se)
监听会话级别属性的增加,即HttpSession.setAttribute(...,...)
void attributeRemoved(HttpSessionBindingEvent se)
监听会话级别属性的删除,即HttpSession.removeAttribute(...)
void attributeReplaced(HttpSessionBindingEvent se)
监听会话级别属性的替换,即HttpSession.setAttribute(...,...)
请求级别:
ServletRequestListener
void requestDestroyed(ServletRequestEvent sre):监听请求的删除
void requestInitialized(ServletRequestEvent sre):监听请求的创建
ServletRequestAttributeListener
void attributeAdded(ServletRequestAttributeEvent srae)
监听请求级别属性的增加,即HttpServletRequest.setAttribute(...,...)
void attributeRemoved(ServletRequestAttributeEvent srae)
监听请求级别属性的删除,即HttpServletRequest.removeAttribute(...)
void attributeReplaced(ServletRequestAttributeEvent srae)
监听请求级别属性的替换,即HttpServletRequest.setAttribute(...)
注:Listener程序不需要我们去调用,它由相应的事件触发执行
配置文件中:<listener>
<listener-class>ch07.ContextListener</listener-class>
</listener>
|