使用JSP/Servlet技术开发新闻发布系统

           第一章:动态网页开发基础 

动态网页:是指在 服务器端运行的,使用程序语言设计的交互式网页,它们会根据某种条件的变化,返回不同的网页内容
动态网页需要使用服务器端的脚本语言,例如:JSP技术就是使用Java+HTML
动态网页的优势:
1:交互性:
      网页会根据用户的要求和选择而动态改变和显示内容
2:自动更新:
      无须改变页面代码,便会自动生成新的页面内容,可以大大节省工作量
3:随机性:
    当不同的时间、不同的人访问同一网址时会产生不同的页面效果
     例如:普通用户和管理员登录论坛时看到的页面效果内容是不同的
B/S(Browser/Server)架构技术
QQ聊天软件就是一个典型的C/S(Client/Server)
基于B/S架构的Web应用程序由于不再受安装客户端的限制,访问及其简便,因此被越来越多的企业采用,在此需要特别说明的是B/S架构的出现不是对C/S架构的一种变化或者改进。
B/S架构是随着Internet技术的兴起,对C/S架构的一种改进而非C/S的替代品
B/S架构的优势:维护和升级方式简单
B/S架构中,软件应用的业务逻辑完全在服务器端实现所有的客户端只是浏览器,不需要做任何的维护。因此系统管理员只需要关注服务器的软件升级即可。客户端只要重新登录系统,使用的就是最新版本的软件了
B/S架构的劣势:在速度和安全性上需要花费巨大的设计成本。
而且由于B/S架构的交互式请求/响应的模式,一旦数据信息发生变化,必须要通过刷新页面,才能看到更新的数据信息
什么时候用C/S?
C/S一般面向相对固定的用户群,一般高度机密的信息系统采用 C/S架构
如:企业内部的信息管理系统,金融证券管理系统
什么时候用B/S?
B/S适用于公开信息发布,对信息的保密性要求较低,如企业网站、售后服务系统等

B/S架构的工作原理

只有浏览器解释执行完HTML文件,才能呈现结果界面
URL(Uniform Resource Locator)统一资源定位符
HTTP:(Hyper Text Transfer Protocol)超文本传输协议  Transmisstion
百度ip:202.108.22.5但常常使用它的域名baidu.com

Tomcat端口号的配置
在Tomcat目录下找到子目录conf------server.xml
用ctrl+f 查找 Connector port="8080",其中8080可改为6060修改后重新启动Tomcat目录结构

Web目录结构

在Tomcat的运行过程中,Tomcat类加载器会首先加载classes目录下的class文件,然后再加载lib目录下的类,需要注意的是,如果在classes目录下和lib目录下存在同名的类,那么classes目录下的类具有优先权
每个java web 应用都有一个核心文件,即web.xml,此文件必须保存在web-inf目录下,因为该目录客户端不可访问,他控制整个应用的行为和方法
   配置web起始访问页面:
在web.xml文件中
 <welcome-file-list>
    <welcome-file>index.jsp---(这里可以改成html文件)</welcome-file>
  </welcome-file-list>  

webapps目录用于进行web项目的发布





实现动态网页的关键就在于运行在服务器端的脚本语言
jsp的优点是:跨平台,易维护,易管理
实际上jsp就是在html中嵌入java的脚本语言
jsp的执行步骤:
翻译:成java源文件
编译:java源文件编译成class文件:二进制字节码文件
运行:class文件
当第二次发生相同的jsp请求时,就可以直接运行class文件
,所以JSP第一次请求时会比较慢,后续会很快
jsp页面由静态内容、指令、表达式、小脚本、
声明、标准动作、注释等元素构成
静态内容:即HTML文本
日期在java.text.*包中;
<%=
  //有等号的的表示数据,不能写分号,相当于打印的功能
  //使用预定格式将日期转换为字符串
     new SimpleDateFormat("yyyy年MM月dd日HH点").format(new Date())
   %>  
<%! 
    //!表示声明,可以声明成员变量,也可以声明方法----声明方法时必须要有声明符!  
    String declare="this is a declare";
    public static void main(String args[]){
    
    }
 %>   

如果要想知道程序是怎么运行的,因为JSP页面已经翻译成了.java文件,所以我们可以到Tomcat目录下的work目录
(这个目录存放着各个web 应用的servlet 即 java和class文件)


-----------
<!--这是HTML注释代码,客户端 可以 通过浏览器的右键查看源代码看到注释的代码  -->

<%-- 这是JSP注释代码,客户端 不可以 通过浏览器的右键查看源代码看到注释的代码 --%>
<%
    //java单行注释
    /*多行注释*/
    /** 
     文档注释
    */
 %>  
<% %>是在_jspService()这个方法内部进行编码   属于局部变量
<%! %>是在jsp的class类里面进行编码   属于类的成员

JSP的脚本元素包括:表达式、小脚本、声明
 <% %>//这个叫小脚本
  <%= %>//这个叫表达式,表达式的等号和分号不能同时存在,否则就会编译错误!  
<%!  %>//这个叫声明
JSP指令元素
JSP指令元素的作用是通过设置指令中的属性,在JSP中运行时,控制jsp页面的某些特性:<%@   %>
<%@ page language="java" import="java.util.*,com.accp.epet.dao.*,com.accp.epet.entity.*" pageEncoding="UTF-8"%>  
_______
contentType=" text/html;charset=utf-8"  等同于 pageEncoding ="UTF-8"
page 指令是针对当前页面进行设置的一种指令,通常位于jsp页面中的顶端。需要注意的是,page指令只对当前jsp页面有效,但是一个jsp页面中可以包含多个page指令

page指令常用的属性: 
language:指定当前页面所用的脚本语言 <%@  page language="java"  %>  
import:导入java的包
contentType:默认是 " text/html ; charset= ISO-8859-1 "
让每次新建的jsp文件默认的编码是UTF-8


                                                      第二章:JSP数据交互




Validate:验证
Context:上下文
Request:请求  :当前请求(别的请求无效)
Response:响应
Redirect:重定向
Session:会话:当前会话 (可以包含多个请求)在该会话有效期内可以访问
Application:当前服务器(可以包含多个会话):
当服务器启动后就会创建一个application对象,被所有用户共享
page、request、session、application四个作用域对象都有
setAttribute()和getAttribute()方法
而且作用域范围越来越大


1:request对象

是从客户端向服务器端发出请求,包括用户提交的信息以及客户端的一些信息。request对象是javax.servlet.http.HttpServletRequest类的实现实例。

request对象封装了浏览器的请求信息,通过request对象的各种方法可以获取客户端以及用户提交的各项请求信息。

使用request对象获取客户端提交的请求参数的常用方法如下:

1.String getParameter(String name),获取上一页面所提交的参数值的参数值,并以字符串形式返回指定参数的值,如果参数不存在则返回空值。用于表单、链接或网址栏传递参数时,使用此方法。

例如,获取客户端name的参数值:

String name = request.getParameter("name");

2.String[ ] getParameterValues(String name),获取以相同名称命名的表单组件提交的数据,主要用于获取复选框的值,返回值类型是字符串数组String[ ]

例如,获取客户端hobby复选框的所有取值:

String[ ] hobbys = request.getParameterValues("hobby");
       if(hobbys != null)
       {
       out.println("您的爱好有:");
       for(int i=0;i<hobbys.length;i++)
          out.println(hobbys[i]);
       }

3.void setCharacterEncoding(String encoding),设置字符编码方式,用来解决传递非英文字符所出现的乱码问题。

对于以post提交的表单数据

在第一行写:
request.setCharacterEncoding("UTF-8");

对于以get提交的表单数据

提交的数据作为查询字符串被附加到URL 的末端发送到服务器,此时字服务器端调用

setCharacterEncoding()方法就没有作用了,我们需要得到请求参数值之后,进行编码转换

String name=request.getParameter("name");

name=new String(name.getBytes("ISO-8859-1"),"UTF-8"); 
也可以通过TomCat目录下的conf下的server.xml文件,在<Connector>元素中添加URIEncoding 属性,将它的值设置为“utf-8”

<Connector

    port="8080"

    protocol="HTTP/1.1"

     reidrectPort="8433"

    URIEncoding ="UTF-8"

/>

4.RequestDispatcher getRequestDispatcher(String path)----获取请求分配器

返回一个javax.servlet.RequestDispatcher对象该方法的forward()方法用于 转发请求

例如,request.setCharacterEncoding("UTF-8");

实例:使用request对象实现用户注册功能

zhuce.html源代码如下:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>个人信息注册</title>
 
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="this is my page">
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
   
    <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->

  </head>
 
  <body>
    <h1 align="center">个人信息注册</h1>
    <form action="zhuce.jsp" method="post">
        姓名:<input type="text" name="name"><br>
        密码:<input type="password" name="pwd"><br>
        请选择你的职业:
        <input type="radio" name="career" value="农民">农民
     <input type="radio" name="career" value="工人">工人
     <input type="radio" name="career" value="学生" checked>学生
     <input type="radio" name="career" value="教师">教师
     <br>
     你喜欢的城市:
     <select name="city">
       <option value="辽宁省">辽宁省</option>
       <option value="湖北省">湖北省</option>
       <option value="河南省">河南省</option>
       <option value="山东省">山东省</option>
       <option value="江苏省">江苏省</option>
       <option value="湖南省" selected>湖南省</option>
     </select>
     <br>
     请选择你的爱好:
     <input type="checkbox" name="hobby" value="旅游">旅游
     <input type="checkbox" name="hobby" value="看书" checked>看书
     <input type="checkbox" name="hobby" value="游戏">游戏
     <input type="checkbox" name="hobby" value="琴棋书画">琴棋书画
     <br>
     自我介绍:
     <textarea name="intro">自我介绍</textarea>
     <br>
     <input type="submit" name="submit" value="提交">
    </form>
  </body>
</html>
zhuce.jsp源代码如下:

<%@ page language="java" import="java.util.*" contentType="text/html;charset=UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    
   
    <title>个人信息注册</title>
   

  </head>
 
  <body>
    <%request.setCharacterEncoding("UTF-8"); %>
     您的姓名是:<%=request.getParameter("name") %><br>
     您的密码是:<%=request.getParameter("pwd") %><br>
     您的职业是:<%=request.getParameter("career") %><br>
     您喜欢的城市是:<%=request.getParameter("city") %><br>
     您的爱好有:<%String[] hobbys = request.getParameterValues("hobby");
       if(hobbys != null)
       {
       out.println("您的爱好有:");
       for(int i=0;i<hobbys.length;i++)
          out.print(hobbys[i]);
       }
      %>
      <br>
     自我介绍:<%=request.getParameter("intro") %><br>
  </body>
</html>

2:response对象
常用方法:
void addCookie(Cookie cookie):在客户端添加cookie
void sentRedirect(String location);重新定位到新的URL


getRequestDispatcher()与sendRedirect()的区别

1.request.getRequestDispatcher()是请求转发,前后页面共享一个request ; 
response.sendRedirect()是重新定向,前后页面不是一个request。

2.RequestDispatcher.forward()是在服务器端运行; 
HttpServletResponse.sendRedirect()是通过向客户浏览器发送命令来完成. 

3.ServletContext.getRequestDispatcher(String url)中的url只能使用绝对路径; 而

ServletRequest.getRequestDispatcher(String url)中的url可以使用相对路径。因为

ServletRequest具有相对路径的概念;而ServletContext对象无此概念。

RequestDispatcher对象从客户端获取请求request,并把它们传递给服务器上的servlet,html或

jsp。它有两个方法:


2.void include(ServletRequest request,ServletResponse response) 
用来记录保留request和response,以后不能再修改response里表示状态的信息。

 

二者区别: 
response.sendRedirect(url)跳转到指定的URL地址,产生一个新的request,所以要传递参数只有在url后加参 
数,如: 
url?id=1. 
request.getRequestDispatcher(url).forward(request,response)是直接将请求转发到指定URL,所以该请求
 
能够直接获得上一个请求的数据,也就是说采用请求转发,request对象始终存在,不会重新创建。而 
sendRedirect()会新建request对象,所以上一个request中的数据会丢失。 
更具体来说就是这样的: 
redirect 会首先发一个response给浏览器, 然后浏览器收到这个response后再发一个requeset给服务器, 然后 
服务器发新的response给浏览器. 这时页面收到的request是一个新从浏览器发来的. 
forward 发生在服务器内部, 在浏览器完全不知情的情况下发给了浏览器另外一个页面的响应. 这时页面 
收到的request不是从浏览器直接发来了,可能己经用request.setAttribute在request里放了数据.在转到的页 
面可直接用request.getAttribute获得数据。 




重定向的重要应用:

使用重定向技术实现超链接的数据传递
<a href="color.jsp?color=黄色">黄色</a>  

使用超链接进行数据传递时,采用的是get方式提交请求, 如果在传递数据中存在中文, 就会造成乱码,因为request.setCharacterEncoding("utf-8")只适用于post方法提交  所以可以通过 设置tomcat字符集实现
当传递多个数据时,可以用&连接
<a href="color.jsp?color=黄色&id=1">黄色</a>   

Session
//设置10分钟后失效
session.setMaxInactiveInterval(10*60);  
也可以在项目的web.xml中设置  代码片段如下:
<session-config>
    <session-timeout>30</session-timeout>       ------这里的单位是分钟  系统默认会话超时是30分钟  0表示失效   -1表示永不超时
</session-config>

使整个session会话失效:session.invalidate();
如果只想清空session的某个对象 ,则可以调用session.removeAttribute(String key)方法,将指定的对象从session中清除
此时session对象仍然有效
1、概念:Session代表服务器与浏览器的一次会话过程,这个过程是连续的,也可以时断时续的。在Servlet中,session指的是HttpSession类的对象,这个概念到此结束了,也许会很模糊,但只有看完本文,才能真正有个深刻理解。
 
2、Session创建的时间是:
JSP文件在编译成Servlet时将会自动加上这样一条语句 HttpSession session = HttpServletRequest.getSession(true);这也是JSP中隐含的 session对象的来历。
由于session会消耗内存资源,因此,如果不打算使用session,应该在所有的JSP中关闭它。
 
引申:
2)、当JSP页面没有显式禁止session的时候,在打开浏览器第一次请求该jsp的时候,服务器会自动为其创建一个session,并赋予其一个sessionID,发送给客户端的浏览器。以后客户端接着请求本应用中其他资源的时候,会自动在请求头上添加:
Cookie:JSESSIONID=客户端第一次拿到的session ID
这样,服务器端在接到请求时候,就会收到session ID,并根据ID在内存中找到之前创建的session对象,提供给请求使用。这也是session使用的基本原理----搞不懂这个,就永远不明白session的原理。
下面是两次请求同一个jsp,请求头信息:
通过图可以清晰发现,第二次请求的时候,已经添加session ID的信息。
 
3、Session删除的时间是:
1)Session超时:超时指的是连续一定时间服务器没有收到该Session所对应客户端的请求,并且这个时间超过了服务器设置的Session超时的最大时间。
2)程序调用HttpSession.invalidate()
3)服务器关闭或服务停止
 
4、session存放在哪里:服务器端的内存中。不过session可以通过特殊的方式做持久化管理。
 
5、session的id是从哪里来的,sessionID是如何使用的:当客户端第一次请求session对象时候,服务器会为客户端创建一个session,并将通过特殊算法算出一个session的ID,用来标识该session对象,当浏览器下次(session继续有效时)请求别的资源的时候,浏览器会偷偷地将sessionID放置到请求头中,服务器接收到请求后就得到该请求的sessionID,服务器找到该id的session返还给请求者(Servlet)使用。一个会话只能有一个session对象,对session来说是只认id不认人。
 
6、session会因为浏览器的关闭而删除吗?
不会,session 存在于服务器内存中

ServletContext application=this.getServletContext();
            List<User> listUser = (List<User>)application.getAttribute("currentListUser");
            if(listUser == null){
                listUser = new ArrayList<User>();
            }
            listUser.add(user);
            application.setAttribute("currentListUser", listUser);  

page作用域:
   在服务器发送响应或请求转发其它页面或资源后无效
   pageContext对象本身也属于page作用域,具有page作用域的对象被绑定到pageContext对象中
request作用域:
session作用域:
    一个浏览器窗口对应一个session对象,当新开一个浏览器窗口时,会重新创建一个session对象
application作用域:


Cookie:
cookie是由Netscape公司发明的,最常用的跟踪用户会话的方式。它
是由服务器端生成,发送给客户端浏览器的,浏览器会将其保存为某一
个目录下的文本文件,方便下一次请求
cookie的作用:
》》》对特定对象的跟踪:如访问者的访问次数,最后访问时间,路径
》》》统计网页浏览次数
》》》在cookie有效期内,记录用户登录的信息
》》》针对用户的喜好推荐不同的内容
 <%
     //javax.servlet.http.Cookie这个包,当JSP翻译成.java文件时会自动导入
          Cookie c=new Cookie("pwd","123");
          c.setValue("456");
     %>
        <%=
           //c.getMaxAge()----  -1  永不超时 c.setMaxAge(0); 0表示失效
           // c.getPath()----null
           //c.getVersion()---0
          //c.getSecure()//cookie是否安全
        //  c.getName()//只有getName()没有setName(),因为名字不可改
          c.getValue()
         %>  
如果未向cookie中添加数据,当创建session时,sessionid的值cookie的值是一样的,说明sessionid被保存在cookie中
当服务器对一个请求作出处理时,cookie才会被写入客户端
使用setMaxAge(int expiry)时,有以下几种情况:
通常情况下expiry为大于0的整数,表示cookie的有效存活时间
如果设置expiry参数等于0,表示删除cookie
设置expiry参数为负或者不设置,表示cookie会在当前窗口关闭后失效
cookie用于保存不重要的用户信息,重要的用户信息使用session保存
 <%
         response.addCookie(new Cookie("uname","Jack"));
         response.addCookie(new Cookie("pwd","123"));
         response.sendRedirect("look.jsp");
      
       %> 

look.jsp
<%
   Cookie[] cookie=request.getCookies();
   String uname=null;
   String pwd=null;
   if(cookie==null){
   out.println("用户名:"+uname+"  "+"密码:"+pwd);
       return;
   }
   
   for(Cookie c:cookie){
       if(c.getName().equals("uname")){
             uname=c.getValue();
       }else if(c.getName().equals("pwd")){
              pwd=c.getValue();
       }
  } 
   out.println("用户名:"+uname+"  "+"密码:"+pwd);
%> 











                            第五章:使用分层实现业务处理
JNDI(Java Naming and Directory Interface)是一个应用程序设计的API,为开发人员提供了查找和访问各种命名和目录服务的通用、统一的接口,类似JDBC都是构建在抽象层上。现在JNDI已经成为J2EE的标准之一,所有的J2EE容器都必须提供一个JNDI的服务。
JNDI可访问的现有的目录及服务有:
DNS、XNam 、Novell 目录服务、LDAP(Lightweight Directory Access Protocol 轻型目录访问协议)、 CORBA 对象服务、文件系统、Windows XP/2000/NT/Me/9x的 注册表、RMI、DSML v1&v2、NIS。数据库
Tomcat 根目录\conf\context.xml文件为全局的上下文配置文件,对所有的Web应用有效。所以将要发布的信息配置在此问件中,再通过JNDI来查找信息
    ---我们可以在Tomcat中发布一条信息,修改context.xml
   
             <Context>
                 <Environment type="java.lang.String" name="林建辉" value="hello"/>
           </Context>
type:java类名的全称
name:变量名,相对于java:comp/env的路径
value:变量值
 数据库连接池的配置:
(第一步:)
 <Resource name="jdbc/news" auth="Container"
  type="javax.sql.DataSource" maxActive="100"
  maxIdle="30" maxWait="10000"
  username="sa" password="123456"  
          url="jdbc:sqlserver://localhost:1433;DatabaseName=NewsManagerSystem"                      
  driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
/>
<!---
        name:指定resource 的JNDI 名字
       auth:指定管理Resource 的Manager,他有两个可选值:Container和Application
       Container表示由容器创建Resource,Application表示由Web应用创建和管理Resource
       type指定由Resource所属的java全类名
       maxActive:指定数据库连接池中处于活动状态的数据库连接的最大数目
       maxIdel:指定数据库连接池 中处于空闲状态的数据库连接的最大数目,0表示不受约束
       maxWait: 指定数据库连接池 中处于空闲状态的最长时间,
               -1表示无限制(以毫秒为单位), 超出这   时间会抛 出异常
       username:指定连接数据库的用户名
       password:指定连接数据库的密码
       driverClassName:指定连接数据库的JDBC 驱动程序
       url:指定连接数据库的路径
->
(第二步:)
<web-app>   -----在web.xml里配置
  <resource-ref>
     <res-ref-name>   jdbc /news   </res-ref-name>--资源的引用名称---可改
       <res-type>   javax.sql.DataSource   </res-type --资源类型
      <res-auth> Container </res-auth> --指定管理所应用资源的Manager
  </resource-ref>
</web-app>  
(第三步:在Basedao中)
import  javax.naming.*
          //   javax.naming.Context 提供了查找JNDI Resource的接口
             //java:comp/env 为前缀
           Context context=new InitialContext();
            DataSource ds=(DataSource)context.lookup("java:comp/env/jdbc/news");
            con=ds.getConnection();  
还有一种配置数据源的方式,只需要在webRoot 目录下的META-INF目录中,创建一个context.xml文件,添加<Context>节点,然后再写<Resource>
数据源配置完后,要通过数据源访问数据库,还需要添加数据库驱动文件,由于数据源由Tomcat创建并维护,所以必须要把数据库驱动文件放到Tomcat的lib目录下
在使用JNDI获得数据源对象时,可分为如下四个步骤
1:在Tomcat的conf下配置context.xml文件
2:在web应用程序的web-inf下配置web.xml文件
3:添加驱动-------jdbc.jar
4:进行代码编写,使用loopup( "java:comp/env/jdbc/news" )方法获得数据源对象
"java:comp/env+数据源名称

什么是连接池?
数据库连接是非常占用系统资源的,这一点在多用访问的应用程序中体现得尤为突出,对数据库连接的管理   会影响到整个应用程序的伸缩性和健壮性。数据库连接池这是针对这个问题提出来的。
数据库连接池负责分配、管理和释放 数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建一个,它会释放空闲时间超过最大空闲时间的数据库连接
日常生活中的实例:拨打10086热线
热线电话对外是相同的号码,允许同时接入多个电话,但是当所有的接入都在工作,再有电话接入时,就需要等待,直到其中一个接入出现空闲

连接池如何管理连接?
  对于连接池的管理可用空闲池,每当用户请求一个连接时,系统先会检查空闲池内有没有空闲连接如果有就分配一个连接给用户;如果没有则检查当前连接池是否达到连接池所允许的最大连接数。如果没有达到,就新建一个连接。如果已达到就等待一定时间,如果在等待的时间内有连接被释放出来,就可以把这个连接分配给等待的用户。如果等待时间超过预定时间,则返回null , 系统对已经分配出去正在使用的连接只做计数,当使用完后再返回给空闲池
数据源与连接池:
数据源是在JDBC 2.0 中引入的一个概念,在JDBC 扩展包中定义了javax.sql.DataSource接口
它负责建立与数据库的连接,在应用中访问数据库是不必编写连接数据库的代码,可以直接从数据源获得   数 据库连接,配置好的数据库连接池也是以数据源的形式存在,这样做可以提高访问数据库的效率。
在传统模式下,数据库连接使用完毕后,需要将其关闭,释放资源,而在连接池中,使用数据源获得数据库连接对象,在调用close()方法时并不会真正地关闭连接,而仅仅是实现了断开应用程序与连接池的联系,即将连接的使用权归还给连接池



JSP 分页显示数据
使用存储过程进行分页,但是需要设置主键和索引提高查询效率,并且可移植性不高;
比较好的分页做法是:每次翻页只从数据库中检索出本页需要的数据。虽然每次翻页都查询数据库,但是查询出的记录很少,网络传输量不大,再配以连接池技术,效率将极大的提高。而在数据库端也有各种成熟的技术用于提高查询速度


基于方便代码管理和逻辑清晰的考虑 将步骤中有关分页的数据封装到一个page类中
package com.accp.news.entity;
import com.accp.news.dao.*;
public class NewsPage {
    private int total;//总共有X个数据       (数据库查询count(*))
    private int pageCount;//每页M个         (程序设计)
    private int pages;//总共需要Y个页面    (X/M+(X%M==0?0:1))
    private int currentPage;//第N页         (1,2,3,4,5,6,Y)
    public NewsPage() {
        super();
        
        this.total = new NewsDaoSQLServerImpl().getAllNewsCount();
        this.pageCount = 5;
        this.pages = (this.total/this.pageCount+(this.total%this.pageCount==0?0:1));
        this.currentPage = 1;
     }  
       //省略各种get set方法
}  
这个暂时先留着:


用Commons-FileUpload.jar 包实现文件上传
  实现文件上传,涉及对文件的读写操作,实现起来需要编写大量的代码,并容易引发异常。幸运的是
        目前有很多非常实用的文件上传工具,可以帮助我们实现文件上传的功能,其中应用比较比较多的是Commons-FileUpload组件,使用该组件可以极大的简化开发人员的编码工作量

Commons是Apache开放源代码组织的一个java子项目,该项目主要涉及一些开发中常用的模块,如文件上传、命令行处理、数据库连接池等。FileUpload 就是其中的一个用于处理HTTP文件上传的子项目
Commons-FileUpload组件具有以下几个特点:
--》使用简单:Commons-FileUpload组件可以方便地嵌入JSP文件中,在JSP文件中仅编写少量代码即可完成文件上传的功能,十分方便
--》能够全程控制上传内容:使用Command-FileUpload组件提供的对象和操作方法,可以获得全部上传文件的信息,包括文件名称、类型、大小等、方便操作

表单的属性设置:
文件上传时,需要在表单属性中添加属性enctype ,该属性用于设置表单提交数据的编码方式。
由于文件传至服务器时与一般的文本类型的编码方式不同,它需要使用multipart/form-data编码方式
 <body>
    <form action="doupload.jsp" method="post" enctype="multipart/form-data">
       <p>姓名:<input type="text" name="user" value="林建辉"></p>
       <div id="imgFileDiv">
            <span id="addFile"><a href="#">批量上传图片</a></span>
            <p>选择图片:<input type="file" name="nfile"></p>
            <p> <input type="submit" name="提交"></p>
       </div>
    </form>
  </body>  
注意:上传文件时,form标签的method属性必须取值为post 不能为get
表单的enctype属性有以下三个值:
application/x-www-form-urlencoded :表示默认值
          作用:用于处理少量文本数据的传递,在想服务器发送大量的文件包含非ASCII字符的文本或二进制数据时效率很低
multipart/form-data: 上传二进制数据
    只有使用了multipart/form-data才能完整地传递文件数据,进行上传操作
    text/plain:
       主要用于向服务器传递大量文本数据,比较使用于电子邮件的应用

<%@ page import="javax.servlet.jsp.tagext.TryCatchFinally"%>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ page import="java.io.*,java.util.*"%>
<%@ page import="org.apache.commons.fileupload.*"%>
<%@ page import="org.apache.commons.fileupload.disk.*"%>
<%@ page import="org.apache.commons.fileupload.servlet.*"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
</head>
<body>
    <%
        request.setCharacterEncoding("UTF-8");
          String uploadFileName="";//上传的文件名
          String fieldName="";//表单字段元素的name属性
          //请求信息中的内容是否是multipart类型,然后把请求对象作为参数穿进去
         boolean isMultipart=ServletFileUpload.isMultipartContent(request);
         //上传文件的存储路径(绝对路径
 String uploadFilePath                =request.getSession().getServletContext().getRealPath( "upload/" );
          if(isMultipart){ //因为我要上传二进制文件,所以必须要判断
             FileItemFactory factory=new DiskFileItemFactory();
             ServletFileUpload upload=new ServletFileUpload(factory);
                          upload.setSizeMax(1024*1024) //控制文件上传的大小 这一行可不写
             try{
               //解析form表单中所有的文件
               List<FileItem> items=upload.parseRequest(request);
                 Iterator<FileItem> ite=items.listIterator();
               while(ite.hasNext()){//循环迭代每个文件
                  FileItem item=ite.next();
                  if(item.isFormField()){//判断是否为普通表单字段元素
                     fieldName=item.getFieldName();//表单字段元素的name属性
                     if(fieldName.equals("user")){
                          //输出表单字段的值
                          out.print(item.getString("utf-8")+"上传了文件.<br/>");
                     }
                  }else{
                          //否则为文件表单字段元素
                        fileName=item.getName();
                     if(fileName!=null && !fileName.equals("")){
                         File fullFile=new File(fileName);
                         File saveFile=new File(uploadFilePath,fullFile.getName());
                         item.write(saveFile);
                         uploadFileName=fileName;
                         out.print("上传文件成功后的文件名是:"+uploadFileName);
                     }
                  }
               }
                        
             }catch(Exception e){
                e.printStackTrace();
             }
          }
    %>
</body>
</html>

ServletFileUpload 类
public void setSizeMax(long sizeMax)   设置请求消息实体内容的最大允许的字节数
public List parseRequest(HttpServletRequest request)
   解析form表单的每一个字符的数据,返回一个FileItem对象 List集合
public static final boolean isMultipartContext(HttpServletRequest request)
       判断请求信息的内容是否是"multipart/form-data"类型
public void setHeaderEncoding(String encoding)
       设置转换时所使用的字符集编码


FileItem 接口
FileItem 是一个接口用于封装单个表单字段元素的数据,一个表单字段元素对应一个FileItem对象
在应用程序中使用的是接口的实现类DiskFileItem类,FileItem接口提供的常用方法:
public boolean isFormField()
         判断FileItem对象封装的数据类型 普通表单字段返回true,文件表单字段返回false
public Stirng getName()  
      获得文件上传字段中的文件名,普通表单字段返回null
public String getFiledName()
            返回表单字段的name 属性值
public void write(File file)
           将FileItem对象中的主体内容保存到指定的文件中
public String getString(String encoding)
          将FileItem对象中保存的主体内容以一个字符串的形式返回。
public long getSize() 
         返回单个上传文件的字节数

FileItemFactory 接口与实现类
ServletFileUpload 对象的创建需要依赖于FileItemFactory 工厂,将获得的上传文件FileItem对象
  保存至服务器硬盘。FileItemFactory接口的实现类是DiskFileItemFactory
public void setSizeThreshold(int size) ------- Size Threshold 门限
                     设置内存缓存区的大小
public void setRepositotyPath(String path) ------ repository 仓库--贮藏室
                        设置临时文件存放的目录








JSP +Servlet+javaBean

  V------C ------M





HttpServlet 是一个抽象类  表示一个抽象类
所有自定义的servlet 都会默认继承此抽象类,实现其所有的抽象方法

HttpServlet类之所以是一个抽象类就是因为它有个抽象方法 service()

javax.servlet.GenericServlet
定义一个通用的,与协议无关的servlet   (Defines a generic, protocol-independent servlet)  。写在Web上使用的HTTP Servlet,扩展了HttpServlet来代替。

GenericServlet类实现了 javax.servlet.Servlet  和的 javax.servlet.ServletConfig  接口。 GenericServlet类可以由一个servlet可以直接延长,虽然它的扩展协议特定的子类更常见,如HttpServlet。

GenericServlet类使得编写servlet更加容易。它提供的生命周期方法的简单版本的init和破坏,并在ServletConfig接口的方法。 GenericServlet类也实现了日志的方法,在ServletContext接口中声明。

要编写一个通用的servlet,你只需要重写抽象的服务方法。
















                   Servlet 基础                           
                                            

一:在本章我们将学到如下的内容

》HTTP协议原理

》服务器端Web编程原理

》Servlet与Web容器

》Java Web应用程序的组成

》Tomcat介绍

 

一:1.1解析HTTP协议

HTTP:超文本传输协议(HyperText Transfer Protocol)

HTTP是一种无状态的协议,意思是指在Web浏览器和Web服务器之间不需要建立持久的连接。

HTTP是遵循请求/响应(Request/Response)模型的。

HTTP处理流程:

 

 

1.1.1建立连接

在java底层代码中是这样实现的,只不过浏览器已经帮我们做了!

1.1.2 发送请求信息  一旦建立的TCP连接,Web浏览器就会向Web服务器发送请求命令。HTTP协议将请求封装成HTTP请求,他包括请求行,请求头,空行,消息体。

1.1.3 回送响应信息

1.1.4 关闭连接

 

1.2 Web服务器的缺陷;

只能向客户端提供静态网页内容
增加一个辅助应用生成动态页面 

辅助的在服务器端进行注册,根据参数查找并运行。

1.3 服务器端网页编程

建动态服务器端内容的过程
–CGI技术
–微软的ASP和ASP.NET技术
–基于Java的Servlet/JSP技术
 
 
1)CGI技术
CGI即通用网关接口(Common Gateway Interface)
最大优点是它可以用Shell、Perl、C、PHP、Python等编写  
但是CGI技术也有缺陷:

每次请求就打开一个CGI进程,严重消耗服务器资源。极大地限制了一个服务器可以支持的并发 CGI用户数量 。

2)java的解决法案

 

    Web容器;

负责管理和运行Servlet的容器叫Web容器
容器对Servlet的支持包括
–通信支持
–生命周期管理
–多线程支持
–JSP支持

-处理安全性

    Servlet

1:Servlet是常规的Java代码。代码中用了一些新的API,但是不涉及新的语法。

2:Servlet代码中有我们不熟悉的重要语句。Servlet不属于J2SE,它属于单独的规范。

3:Servlet对标准类(HttpServlet)进行了扩展。

4:Servlet没有main()方法。


这章我们主要的目标

理解Servlet

Servlet的编码和部署
Servlet生命周期
Servlet的配置
Servlet与容器交互 
 
什么是Servlet?


在JSP技术出现之前,如果想动态生成HTML页面,那就只有在服务器端云行java程序

并生成HTML格式的内容 ,Servlet就  是运行在Web服务器或应用服务器上的Java程序

Servlet实际上就是按照Servlet规范编写的一个java类,它主要用于处理客户端请求并作

出响应
-在Web上创建动态内容的有效而强大的解决方案
-由容器来管理生命周期与Web服务器交互
-由Sun规范了其功能 
 
Servlet的规范组成  
Web应用程序  Servlet和HTTPServlet   过滤器  安全  国际化  
 
 Servlet API 

HttpServlet的public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException;

            

       这是一个Servlet的HTTP-specific方案,它相当于一个分配器,可以根据


请求方法 的类型调用相应的doXxx()方法

      

当你开发Servlet时,在多数情况下你不必重载这个方法。

 


ServletConfig接口

Servlet容器使用ServletConfig对象在Servlet初始化期间向其传递配置信息

       定义

       public interface ServletConfig

       这个接口定义了一个对象,通过这个对象,Servlet引擎配置一个Servlet并且允许Servlet获得一个有关它的ServletContext接口的说明。每一个ServletConfig对象对应着一个唯一的Servlet。

       方法

       1、getInitParameter

       public String getInitParameter(String name);

       这个方法返回一个包含Servlet指定的初始化参数的String。如果这个参数不存在,返加空值。

       2、getInitParameterNames

       public Enumeration getInitParameterNames();

       这个方法返回一个列表String对象,该对象包括Servlet的所有初始化参数名。如果Servlet没有初始化参数,getInitParameterNames返回一个空的列表。

       3、getServletContext

       public ServletContext getServletContext();

       返回这个Servlet的ServletContext对象。


 详情请看ServletAPI手册

 

Servlet生命周期
Servlet不能独立运行,它必须被部署到Servlet容器中,由容器实例化和调用Servlet的方法

Servlet容器在Servlet的生命周期内管理Servlet,当Servlet容器启动或者当客户端发送一个请求时,Servlet容器会在内存中查找是否存在该Servlet容器,如果不存在,就创建一个Servlet实例,如果存在该Servlet实例,就直接从内存中取出该实例响应请求
加载和实例化、初始化、处理请求、销毁
Tomcat服务器停止时,destory()方法才被执行
初始化和 销毁通常执行一次,服务可以执行多次。
所有的Servlet必须实现javax.servlet.Servlet接口。这个接口定义了  init();service(ServletRequest req, ServletResponse resp);destory();
 
 
Servlet的编码和部署

 
在web.xml中部署servlet

<servlet>
      <servlet-name>OutputStream</servlet-name>
      <servlet-class>com.cy.OutputStream</servlet-class>
</servlet>

映射servlet:

<servlet-mapping>
       <servlet-name>OutputStream</servlet-name>
       <url-pattern>/OutputStream</url-pattern>
</servlet-mapping>

 

servlet配置:

为Servlet提供初始化配置信息
配置信息由web.xml声明中的字符串组成
 
eg:
<web-app>
   <!--上下文参数在servlet标签外-->
<context-param>
       <param-name>contextName</param-name>

     <param-value>name</param-value>

</context-param>

<servlet>

    ....

  <init-param>

     <param-name>name</param-name>

     <param-value>Kitty</param-value>

  </init-param>

<load-on-startup>2</load-on-startup>//加载顺序排第二

</servlet>

</web-app>


java中<load-on-startup>含义
    java中的load-on-startup用于表示该servlet是否在servlet容器启动的时候加载。
示例:<load-on-startup>xx</load-on-startup>
其中:如果xx是负数或者其他数值或者没有指定,表示该servlet在被选择时才加载;
      如果xx为正数或者为0,表示在servlet容器启动的时候就加载,而且数值越小,加载的优先级越高!

注意:有些初始值需要servlet容器在启动的时候就应该加载到内存中,所以很有必要设置这些初始值在启动的时候就应该加载,这种情况下就可以设置这个servlet的load-on-startup属性


Servlet在编译的代码之外有初始化参数,当参数改变时,不需要重新编译Servlet  ,每个servlet都有一个与之相联的对象ServletConfig; (在servletConfig对象中包含了servlet的初始化参数信息。)

得到指定的参数value:String value= getServletConfig().getInitParameter(“name"); 

也可以这么写:String value= this.getInitParameter(“name"); //this可省

得到所有的所有的参数value:需要应用一个ServletConfig中的一个方法:getInitParameterNmes():返回一个Enumeration(枚举)对象,里面包含了所有的初始化参数。

 

  1. Enumeration e = this.getServletConfig().getInitParameterNames();  
  2.         while(e.hasMoreElements()){  
  3.             String name = (String)e.nextElement();  
  4.             String value = this.getServletConfig().getInitParameter(name);  
  5.             System.out.println(name+"="+value);  
  6.         }  
  7.     }  
 获得上下文参数:
String value=this.getServletContext().getInitparameter("contextName");

  1. import java.io.IOException;  
  2. import java.io.PrintWriter;  
  3. import java.util.Enumeration;  
  4.   
  5. import javax.servlet.ServletException;  
  6. import javax.servlet.http.HttpServlet;  
  7. import javax.servlet.http.HttpServletRequest;  
  8. import javax.servlet.http.HttpServletResponse;  
  9. /**  
  10.  * 获取Http协议的请求行,请求头  
  11.  * @author Starjuly  
  12.  *  
  13.  */  
  14. public class RequestDemo1 extends HttpServlet {  
  15.   
  16.        
  17.     public void doGet(HttpServletRequest request, HttpServletResponse response)  
  18.             throws ServletException, IOException {  
  19.         System.out.println("请求行的方法:" + request.getMethod());  
  20.         System.out.println("请求行的URI:" + request.getRequestURI());  
  21.         System.out.println("请求行的URL:" + request.getRequestURL());  
  22.         System.out.println("请求行的版本:" + request.getProtocol());  
  23.           
  24.         System.out.println("请求头:"+request.getHeader("User-Agent"));  
  25.         //利用迭代器遍历所有的请求头  
  26.         Enumeration names = request.getHeaderNames();   
  27.         while(names.hasMoreElements()){  
  28.             //获取请求头  
  29.              String  nextElement = (String)names.nextElement();  
  30.              //获取每个请求头的内容  
  31.              String header = request.getHeader(nextElement);   
  32.              System.out.print(nextElement+" : ");  
  33.              System.out.println(header);  
  34.         }  
  35.           
  36.     }  
  37.   
  38.        
  39.     public void doPost(HttpServletRequest request, HttpServletResponse response)  
  40.             throws ServletException, IOException {  
  41.   
  42.         doGet(request,response);  
  43.     }  
  44.   
  45. }  

ServletContext 应用上下文:
 
属于整个Web应用程序
可以访问到Web应用程序资源的本地输入流
把资源的虚拟路径转换为物理路径
记录事件日志
绑定一个对象在整个Web应用程序中共享
 
初始化web应用程序参数:

 <web-app>

 …

 <context-param>

     <param-name>admin email</param-name>

     <param-value>admin@cy.com</param-value>

  </context-param>

     …

</web-app>

 

在Servlet中共享信息

为所有的Servlet设置一个实时变化的参数值
在Web应用程序中共享一个对象
eg:

servletContext.setAttribute("password", "tiger");

String password = (String) servletContext.getAttribute("password");

虚拟路径转换为物理路径:

getResourcePaths(java.lang.String path):返回一个集合,路径必须从Web应用程序的根“/”开始;

getResourceAsStream(java.lang.String path):返回一个InputStream对象。当一个资源需要逐字节读取的时候该方法比较适用。

getResource(java.lang.String path):返回一个Web资源列表。



Servlet与jsp 的区别:
JSP在本质上就是Servlet,但是两者的创建方式不一样.Servlet完全是JAVA程序代码构成擅长于流程控制和事务处理而通过Servlet
来生成动态网页;JSP由HTML代码和JSP标签构成,可以方便地编写动态网页
因此在实际应用中采用Servlet来控制业务流程,而采用JSP来生成动态网页.在struts框架中,JSP位于MVC设计模式的视图层,而Servlet位于控制层.
答案2:
JSP是Servlet技术的扩展,本质上就是Servlet的简易方式。JSP编译后是“类servlet”。Servlet和JSP最主要的不同点在于,Servlet的应用逻辑是在Java文件中,并且完全从表示层中的HTML里分离开来。而JSP的情况是Java和HTML可以组合成一个扩展名为.jsp的文件。JSP侧重于视图,Servlet主要用于控制逻辑。




回顾上一章的知识:
Java Servlet是运行在Web服务器或应用服务器上的Java程序
Servlet规范对Servlet功能进行了严格定义
Servlet API与容器进行通讯
Servlet的编码和部署
Servlet需要在容器中进行注册和映射
容器管理Servlet的生命周期
SevletConfig对象为Servlet提供初始化参数
ServletContext对象属于整个Web应用程序
 
本章学习知识:
回顾HTTP请求的处理过程(回顾第一章)
设置HTTP状态码
设置HTTP响应头
设置HTTP消息体
请求重定向和自动刷新页面
 

设置HTTP状态码

设置响应状态行:
HTTP状态码:

HTTP状态码:

100-199:表示信息性代码,标示客户端应该采取的其他动作,请求正在进行。

200-299:表示客户请求成功。

300-399:表示用于已经移走的资源文件,指示新的地址。

400-499:表示由客户端引发的错误。

500-599:表示由服务器端引发的错误

servlet设置状态码一般使用HttpServletResponse的setStatus()方法;

设置HTTP响应头

HttpServletResponse对象用于操纵响应的HTTP头
目的用于告诉客户端
–发送回来的内容的类型
–有多少内容正被发送
常用的方法:

setContentType(String mimetype);

addCookie(Cookie c);

发送内容的服务器的类型

设置HTTP消息体

HttpServletResponse对象负责将信息返回给客户端

HttpServletResponse对象只产生一个空的HTTP响应

传回自定义的内容需要使用getWriter()或者getOutputStream()方法

–传送普通文本

–传送二进制内容 

 

请求重定向和自动刷新页面

重定向的原理:(看三张图片):

         

            

          

使用sendRedirect(String URL)方法实现重定向,

 

在指定时间内自动刷新当前页或到一个新的页面
根据时间来控制响应
想在响应中有一个短时间的暂停 

response.setHeader("Refresh", "time; URL=url" );

 总结:
请求URL时HTTP发出了多个请求
状态码告诉浏览器发送的内容及格式状态
Servlet API与容器进行通讯
HttpServletResponse定义的常量来避免直接使用整数
在通过PrintWriter对象发送任何内容之前先调用 HttpServletResponse的setStatus()方法
为了让Servlet发挥最大的效能,HttpServletResponse对象用于操纵响应的HTTP头
getWrite()或者getOutputStream()方法传送文本或者二进制内容给客户端
sendRedirect方法实现重定向
HTTP响应头“Refresh”会根据时间来控制响应

回顾上一章的知识:
请求网络资源HTTP会发出多个请求并得到响应
设置响应状态行关键是设置状态码
在向客户端输出内容之前要设置状态码和响应头
设置响应头让Servlet发挥最大功能
消息体可以用文本或二进制流方式发送
响应重定向把请求转发给另外一个URL,利用302状态码和Locatoin头,让浏览器处理
可以根据时间来控制响应
 
本章目标:
HTTP请求提交的方法
获取HTTP请求行与请求头
获取表单数据
请求派发和请求范围
 
GET/POST提交方法:
浏览器向Web服务器发送HTTP请求
–用户在网页上点击一个超连接
–用户提交在网页上填写好的表单
–用户在浏览器地址栏中输入URL地址并回车 
默认情况下都是使用HTTP协议的GET方法提交请求
 
GET/POST提交方法区别:
 

何时使用GET/POST方法:

1:请求一个静态页面或图形文件时使用GET方法,因为仅仅需要发送文件名;

2:发送大数据的时候,使用POST方法;

3:上传文件时,使用POST方法;

4:发送用户名、密码或其他保密信息的时候使用POST方法;
 
获取HTTP协议请求行:
HttpServletRequest对象的如下方法访问
–getMethod():获取HTTP的请求方法,例如GET、POST等

-getRequestURI():获取请求的URI资源

–getRequestURL():获取请求的URL,包含协议名、服务器名或IP、端口号和请求资源但不包括查询字符串参数
–getQueryString():获取请求URL后面的查询字符串
–getProtocol():获取HTTP的协议名和版本号
–getContextPath():获取请求URI资源的上下文路径
–getServletPath():获取Servlet的映射路径
 
获取HTTP协议请求头:
HTTP请求头用于告诉服务器客户端使用什么软件以及客户端想要服务器如何返回请求的信息
HttpServletRequest对象的如下方法访问
–getHeader(name):返回指定的请求头的值
–getHeaders(name) :返回一个Enumeration(枚举)包含请求头中的所有值
–getHeaderNames():特定请求中接受到的所有请求头的名称
–getIntHeader(name):获取特定请求头的值,并将其转化为int类型
–getDateHeader(name):获取特定请求头的值,并将其转化为Date类型  
 

Enumeration enum = request.getHeaderNames();

      while (enum.hasMoreElements()) {

          String headerName = (String) enum.nextElement();

         String headerValue = request.getHeader(headerName);

        out.print("<b>"+headerName + "</b>: ");

        out.println(headerValue + "<br>");

      }

 

获取请求消息体:

消息体可以是普通文本也可以是二进制数据 
HttpServletRequest对象可以使用通用的方法来获取表单数据
 
请求转发和请求方法:
重定向和请求转发之间最大的区别在于,重定向让客户端浏览器来完成,而请求转发是在服务器端做工作。
请求转发:
RequestDispatcher对象可以通过调用ServletRequest对象的方法:getRequestDispatcher(String path);
RequestDispatcher对象提供了两种方法来包含资源以及请求转发到不同的资源:
forward(ServletRequest, ServletResponse):派发请求和响应对象到RequestDispatcher 对象所确定的新资源(Servlet、JSP或者HTML等)
include(ServletRequest, ServletResponse):该方法关键是能包含服务器端的资源 
总结:
HttpServletRequest对象主要用于处理分析请求
默认情况下,使用HTTP协议的GET方法提交请求
HTML表单通过“method”属性使浏览器使用HTTP POST方法
GET/POST方法适用于不同场合
HttpServletRequest对象中最常用的方法是获取请求表单参数
HttpServletRequest对象也可以得到请求中参数的原始字节数据
重定向和请求派发之间最大的区别在于,重定向让客户端浏览器来完成,而请求派发是在服务器端做工作
HttpServletRequest可以把一个对象用名字绑定在请求范围内,并且进行访问和删除

状态管理概述
Cookie
Session
URL重写
 
状态管理概述:
HTTP协议使用的是 无状态的连接
对容器而言,每一个请求都来自于一个新的客户
这里我们有四种方法来解决这个状态:
a:表单隐藏字段
b:Cookie
c:  Session
d:  URL重写
 
我们就来一一介绍这四种方案:
A:状态管理解决方案-表单隐藏字段
   表单隐藏字段:
<input type="hidden" name="session"  value=""/>

1:对用户在网站上的访问进行会话跟踪。

2:为服务器端程序提供预定义的输入。

3:存储动态产生的页面上下文信息。  

隐藏字段存在一个主要的缺点,即只有每当每个页面都是动态生成的时候才有效。

 

 

B:表单是在生成动态时才有效,那么我们就使用HTTP Cookie来固定的保存在某个地方,需要是读取。

 

使用HTTP Cookie可以很好的维护和保留用户的状态信息,但是Cookie涉及到一些敏感的隐私问题,一些用户会禁用Cookie,这时我们需要另一个方法来解决

 

C:URL重写

 

D:Servlet提供了出色的解决方案,HttpSessionAPI,这种高级接口建立在Cookie和URL重写之上。

把客户的状态信息保存在服务器端

Session对象就是服务器为客户端创建并维护的用于存放客户状态数据的对象 

 

一:Cookie

1:Cookie原理:

服务器在响应请求时将一些数据以“键-值”对的形式通过响应信息保存在客户端,当浏览器再次访问相同的应用时,会将原先的Cookie通过请求信息带到服务器端。

Cookie cookie = new Cookie("cool", "tiger!");

response.addCookie(cookie); 

2:在Serlvet中管理Cookie

Servlet中提供了如下一系列操作Cookie的API
–Cookie(name, value):构造方法用于创建一个或多个Cookie
–setMaxAge(int lifetime):设置Cookie的过期时间(以秒为单位)。默认值为负值(Cookie将在浏览器关闭时过期)
–getMaxAge():获取Cookie的过期时间。
–getName():获取Cookie的名字
–setValue(String value):指定Cookie的值。
–getValue():获取Cookie的值
-.......
 
3:在Servlet中使用Cookie
要将Cookie发送到客户端,Servlet应该按照下列的操作步骤执行:
–创建一个或多个Cookie,使用构造方法指定Cookie的名字和值
–使用setXXX方法为Cookie设置属性值
–使用HttpServletResponse对象的addCookie()方法将Cookie插入到响应头中
要读取客户端传入的Cookie,Servlet执行下列操作步骤:
–使用HttpServletRequest对象的getCookie方法返回一个Cookie对象数组
–Servlet遍历该数组(调用getName()方法),直到找到与名称相匹配的Cookie值
 
 
 
二:Session
1:Session原理
-服务器可以为客户端创建并维护一个Session对象,用于存放数据。
-在创建Session对象的同时,服务器将会为该 Session对象产生一个唯一编号,这个编号称之为SessionID
-服务器以Cookie的方式将SessionID存放在客户端。
-当浏览器再次访问该服务器时,会将SessionID作为Cookie信息带到服务器,服务器可以通过该SessionID检索到以前的Session对象,并对其进行访问
 
2:Session工作流程
 
3:Session会话跟踪机制
 
用户发送请求

HttpSession session = request.getSession(); //getSession(false)方法使用已经存在的会话,而不必创建新会话

服务器的响应
再次发送请求
4:HttpSessoin接口
HttpSession接口常用的一些方法
–setAttribute(java.lang.String, java.lang.Object):在Session对象中用一个名字绑定一个对象。
–getAttribute(java.lang.String):通过名字获取Session对象中保存的对象。
–removeAttribute(java.lang.String):在Session中删除与一个名字对应的对象。
–getCreationTime():返回第一次创建会话的时间。
–getLastAccessedTime():返回容器最后一次得到该会话ID的请求时间。
–setMaxInactiveInterval(int interval):对于会话指定客户请求的最大间隔时间,以秒为单位。-1表示永不过期
–getMaxInactiveInterval(int interval):返回客户请求的最大间隔时间。
–invalidate():会话结束,当前存在在会话中的所有会话属性也会解除绑定。
–getId():此方法返回每个session唯一的标识 
-......
5:会话超时管理
销毁会话可以采用如下三种简单的方式           //浏览器关闭时并不意味着Session对象被删除
–设置会话超时。
–在Session对象上调用invalidate()方法。
–应用结束(崩溃或取消部署)
在web.xml文件中配置    //以分钟为单位

<session-config>

       <session-timeout>15</session-timeout>

  </session-config> 

 6:Session持久化管理

三:URL重写

Session对象的正常使用要依赖于Cookie
URL地址重写能够取得置于Cookie中的会话,并把会话ID附加到访问应用的各个URL最后

URL重写方法:

response.encodeURL()

response.encodeRedirectURL(“/lovobook/sucess.html” )

URL重写是容器自动完成的,但需要我们对URL进行编码才有效 

总结:

1 HTTP协议使用的是无状态的连接,连接只针对一个请求/响应
2 状态管理方案:表单隐藏字段、Cookie、Session、URL重写
3 Cookie是Web服务器发送到客户端浏览器并保存的简短文本信息
4 Session对象就是服务器为客户端创建并维护的用于存放客户状态数据的对象
5 用户会禁用Cookie。这时我们可以使用URL地址重写来解决
6 通过HttpServletResponse的addCookie方法将该Cookie信息添加到响应信息中
7 Session对象是某个Servlet调用HttpServletRequest.getSession()这样的语句时才被创建
8 Session对象是保存在服务器端,浏览器关闭时并不意味着Session对象被删除
9 Session只认SessionID不认人
10 应当尽量使用维护时间短的域对象
11 在向客户返回第一个响应时,会同时尝试设置Cookie和URL重写两种做法 


      
 EL(Expresstion Language)表达式和JSTL(JSP Standard Tag Library)


 <%
               Map map= new HashMap();
               map.put("one","java");
                request.setAttribute( "map" , map);//这句话一定要写,要不然EL获取不到
   %>
   学科:    ${map.one}  


如果map里放的是数字字符串,则在EL表达式的里不能通过 " ."操作符来获取值

只能通过[ ]操作符来获取值,否则会运行时出错














<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>  

<c:set   target="${provinceList[0]}" property="provinceName" value="林建辉" var="u" scope="application" ></c:set>
 <c:out value="${provinceList[0].provinceName }" default="noUname" escapeXml="true"></c:out>
//通过变量名获取值,如果变量名为空,则显示默认值
 <c:out value="${u}" default="noUname" escapeXml="true"></c:out>  

Empty 操作符:

是一个前缀操作符,用于检测一个值是否为null或empty

例如:如果变量a不存在或者变量a 的值为空,则${empty a }  为true   
检查非空用${ not empty a }或 ${ ! empty  a }   

作用域的访问对象:当使用EL表达式访问某个对象时,应该指定查找范围,如

${requestScope.employee}

如果不指定就会按照page---》request---》session--》application

<c:set var="isLogin" value="${!empty sessionScope.user }"></c:set>
  <c:if test="${isLogin }">
    //如果为真执行里面的内容
  </c:if>  


相当于if --else 
 <c:choose >
    <c:when test="${!empty isLogin }">
    
    </c:when>

    <c:otherwise>
    
    </c:otherwise>
  </c:choose>  

使用EL遍历Map集合

<%
    Map<String ,String> map=new HashMap<String ,String>();
    map.put("sssss","dddd");
    map.put("qqqqq","wwwwwww");
    map.put("aaaaaa","bbbbbbb");
    
         request.setAttribute("map", map);
  %>
    <%--一定要写${ } --%>
  <c:forEach var="entry" items="${map}">
        <%--充分说明map里有key属性和 value属性 --%>
      ${entry.key }---${entry.value}<br/>
  
  </c:forEach>  








如果:定义了 var属性,则target属性会被禁止,包括property属性,而且JavaBean对象及property属性
不存在时不会报错

<c:set var="aa" value="2" target="javaBean" scope="request" property="name"></c:set>
  <c:out value="${javaBean.name }"></c:out>  

当没有指定var 变量时,target属性和scope属性不能同时存在,因为此时target对象是一个JavaBean对象  使用${requestScope.user},如果再定义scope属性的话会发生冲突





  • 11
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值