Java Servlets
lgl669
2009-06-17
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> |
相关讨论
相关资源推荐
- VB.net中ByVal ByRef ;形参 实参 区别的描述,带源代码
- 今天你多态了吗?
- item12 使用override声明重写函数
- ByVal与ByRef的区别
- linux编译器警告变成错误,警告就是错误
- ccparticlesystem学习笔记
- 如何在C#中使用托管指针
- C#中“ref“关键字详解及案例
- net core生成数据库,使用Scaffold-DbContext报错“‘Scaffold-DbContext’ is not recognized as the name of a cmdlet”
- The method addUser(User) of type UserServiceImpl must override or implement a supertype method 错误