servlet+jsp05基础知识

13年前
知识复习和扩充:
1、序列化和反序列化
 序列化可以理解为把java对象内存中的数据弄成一串二进制数据,然后把这些数据存放在可以持久化的数据存储设备上。
 当需要还原这些数据的时候,再通过反序列化的过程,把对象数据重新还原到内存中。
 java.io.Serializable接口是可以进行序列化的类的标志性接口,仅用来告诉JVM该类的对象的可以进行的序列化。
 
 所有需要进行序列化的类,都必须实现Serializable接口,必要时还需要提供静态的常量SerialVersionUID
 Java的IO提供过了一对类用作对象的序列化和反序列化,主要包括ObjectOutputStream和ObjectInputStream。
 序列化和反序列化的主要步骤:
  a、让需要序列化的类实现java.io.Serializable
  b、提供静态的long型 常量serialVerisonUID
  c、如果是序列化对象,则用一个输出流创建一个ObjectOutputStream对象,然后调用writeObject()方法
  d、如果是反序列化对象,则使用一个输入流创建一个 ObjectInputStream对象,然后调用readObject(),
   得到一个Object类对象,然后再强转。
  e、最后关闭流
  ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("c:/web/obj.dat"));
  oos.writeObject(要序列化的类class);
  oos.close();
 
  ObjectInputStream ois=new ObjectInputStream(new FileInputStream("c:/web/obj.dat"));
  Object obj=ois.readObject();
  Student stu1=(Student)obj;
  
 
2、JSP的运行机制
 JSP(Java Server Page)是一种建立在Servlet规范提供的功能之上的动态网页技术。
 JSP文件会在用户第一次请求时,web容器(如tomcat)会将该文件编译成servlet,再由该servlet出来用户请求。
 web容器处理请求的过程:
  a、会检验JSP语法是否正确
  b、将该JSP文件转换成Servlet源文件
  c、编译该源码文件成为class文件
  d、创建一个servlet类的对象实例,以servlet的方式为请求提供服务。
3、List、Set、Map
 List:有序存放,可以重复,可以存放不同类型的对象;
 Set:无序存放,不能重复,可以存放不同类型的对象;
 SortedSet:排好序列的Set;
 Map:键值对
 SortedMap:排好序列的Map
 备注:所有的集合实现类,存放的是对象,需要存放基本数据类型的数据,则需要使用其包装类。
 能够迭代查询,Iterator,forEach
5、理解HttpSession
 原理:服务器端的对象,可以用于存储对象
     通过SessionID标识
     SessionID通过cookie来保持
  /*
   * 如果当前的请求信息中有带有存储
   * Session ID的Cookie,且该Session ID
   * 对应的Session对象存在,则返回该对象
   *
   * 否则,该方法将创建新的Session对象
   * 并且将新产生的Session ID 作为Cookie
   * 通过响应存到浏览器端
   */
  HttpSession session = request.getSession();
  
  System.out.println(session.getId());
  
  // void setAttribute(String, Object)
  session.setAttribute("date", new Date());
  
  
  session.setMaxInactiveInterval(60*30);
  //设置最大的不活动时间
  
  // 让Session马上失效,一般用在login的登出
  //session.invalidate();
  
  // Object getAttribute(String)
  Object obj = session.getAttribute("date");
  System.out.println(obj);
6、Session注意的问题
 1、session中的数据不能过大
 2、会话范围,关闭浏览器session“失效”?
    能否不快速失效,因为默认的cookie的最大生存时间为负数,修改下即可。
 3、最大的不活动时间maxInactiveInterval
    控制session对象在服务器端的时效
 4、Session的序列化
    服务器关闭的时候会将其序列化成文件,启动起来的时候会反序列化
API
 setAttribute
 getAttribute
 setMaxInactiveInterval
 invalidate
 getSessionoId
7、分页
  分页查询:只是把数据取一部分出来显示
  分页显示:就是把数据全部取出来,只显示一部分
 
 分页显示:结果都拿出来,然后再分页显示
   select * from emp;
   ...
   int n=1;
   while(rs.next()){
   if (++n>10)
   {
   
   }
   }
 惰性加载
  ResultSet 通过select * from emp查询记录时,可能会从100w条记录内查询
  实际上并没有将100w条记录全部加载到内存中。
  可能通过设置只显示100条记录。
  当游标来访问1-100条记录时,直接访问即可,当超过100条记录时
  会继续将其他记录加载到内存中,记录越来越多,会出现内存不够
 所以,对大数据量来说,分页显示是不行的
***用可滚动的结果集还是游标的next来做分页显示效果都是一样的。只是可滚动的结果集变成要简单些而已***
 
了解IO中的skip(100)

 分页查询
  
  a、oracle用rownum伪列
  select id,name,sal from(select id,name,sal rownum num from emp where rownum<?) where num>=?;
  b、mysql用limit
  select id,name,sal from emp limit (?,?);
  第一个问号表示从哪里开始取
  第二个问号表示一共取几个
8、在web工程中的classes类路径下载入资源文件
 读取数据库的配置文件
  SomeClass.class.getClassLoader().getResourceAsStream("org/whatisjava/dao/db.properties");

5、jsp+javaBean的编程模式
 一堆jsp、一堆java类(封装对数据库的增删改查)
  jsp分三类:1、显示jsp
       2、表单jsp:收集用户信息,提交给另外一个jsp
       3、接收jsp:接收用户的输入。进行一个操作,添加一个员工
需求:
 员工列表
  姓名   id    salary
 

  上一页  2   下一页
  一、table
   emp
  二、javaBean
   首先要想好类名;一般情况下,一个表,对应一个Dao
   Emp
   EmpDao  封装一些方法,对员工数据的增加删除改动查询
  三、jsp页面
   emp_list
  浏览器          jsp              DAO
   | ——〉  |  方法  |    获得第一页的数据
   |     |————〉  |
   | <——  |     |
   | ——〉  |     |   再次发请求,必须显示哪一页n的请求
    |     |————〉  |方法n
    |  <—— |     |
   |     |     |
   |     |     |隐含存在一个返回一个总的页数
   |     |     |
 
 
9、文件的上传
 <form action="upload" method="post" enctype="multipart/form-data">
  ============================================================
      <table cellpadding="0" cellspacing="0" border="0"
       class="form_table">
       <tr>
        <td valign="middle" align="right">
         上传你的照片
        </td>
        <td valign="middle" align="left">
         <input type="file" class="inputgri" name="file1" />
         ==================================================
         //会在页面中显示一个文本框和一个浏览按钮
        </td>
       </tr>
      </table>
      <p>
       <input type="submit" class="button" value="提交 &raquo;" />
      </p>
 </form>

上传图片
抓包分析:
协议头
  POST
  Content-Type:multipart/form-data;  boundary=------------7d392939239239234
  ....
 
    用边界隔开的数据块
 =------------7d392939239239234
 Content-disposition:form-data;name="file1";filename=""
 Content-type:image/jpg

*******如果服务器把这个东西读取出来就相当于把数据上传了。服务器端需要具备能识别这些数据块的组件。
服务器端需要具备能识别这些数据块的组件
我们希望用现成的组件来读取协议里面的东西Apache Commons

企业里面希望我们写出山寨版本的spring,struct,hibernate;怎么写呢?
 实际上大多数框架都是引进了一些小的框架比如hibernate中采用了cglib延缓加载
 也就是把小的框架了解清楚了,才能逐步的写出山寨版的
 
 apache Commons
 Commons
Commons
文件上传:
 
 首先把commons-fileupload-1.2.1.jar复制到项目的lib目录下
 可以做个servlet来实现表单的上传
 
package org.whatisjava.servlet;
import java.io.File;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
public class UploadServlet extends HttpServlet {
 public void service(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException {
  try {
   // 用于设定诸如缓存之类的参数,和性能相关
   // 此处用默认设定
   DiskFileItemFactory dfif = new DiskFileItemFactory();
   //文件项工厂
   // 解析表单中的数据
   ServletFileUpload upload = new ServletFileUpload(dfif);
   //ServletFileUpload是重点
   
   upload.setSizeMax(10 * 1024 * 1024);
   // 允许上传的最大值
   //如果超过这个设置,将不再解析,防止恶意攻击
   List list = upload.parseRequest(request); // 开始解析request对象中的表单数据
   // list中是FileItem对象
   // 一个FileItem用于封装一个上传的文件数据
   
   if (list.size() >= 1) {
    FileItem item = (FileItem) list.get(0);
    
    String name = item.getName();
    // 获得上文件的路径名
    
    name = name.substring(name.lastIndexOf("\\") + 1);
    // 把上传的文件数据写入本地文(服务器端)件
    String path = "pic";
    // Sun的标准,服务器实现的API
    ServletContext ctx = this.getServletContext();
    path = ctx.getRealPath(path);
    
    
    System.out.println(path);
    item.write(new File(path, "default.jpg"));
    //查看api,new File
    response.sendRedirect("upload_form.jsp");
   }
  } catch (Exception e) {
   throw new ServletException("file upload error!", e);
  }
 }
}
 
String path = "pic";    
//sun公司的标准;tomcat服务器实现的api
//ServletContext   servlet的上下文
//
ServletContext  ctx=this.getServletContext()
 
//getServletContext;   将相对路径转换成绝对路径
path = ctx.getRealPath(path);      

//上传图片后,个别时候由于存在缓存,所以可能个别时候不能更改----怎么处理?

10、练习电子相册系统
a、每个用户可以建立自己的个人用户信息,上传自己的图片;
b、游客只能看用户列表,
c、如果需要看姓名,必须登陆,如果没有账户则须注册
d、用户列表
 姓名    年龄   所在地
 姓名是超链接能出来详细的信息,也能看到自己上传的图片
e、加上验证码
f、登录和注册模块
table
 t_user
  u_id   //唯一的主键
  u_username  //最好用email注册
  u_password
  u_name
  u_age
  u_sex
  .....
  u_pic  //上传图片的路径
   该路径可以由pic_uid来区分
  对应每一个用户有一个图片库,最好是另外一台服务器
  
     
 ***假设放置到实际案例中前台采用F5来实现负载均衡,批量的并发用户来自全省各地,怎么分摊其负载呢?
 *** 上传路径不仅要考虑存储的目录还要考虑上传到哪个服务器上了。
 *** 服务器之间数据同步问题?同步时影响带宽和性能问题?
 *** 还是通过磁盘阵列提供的mirror功能来实现数据同步?
首先把登录和注册写了
 1、登录成功后,定位到一个页面,并把登录成功的信息放到session里面
 2、注册是在数据库中增加一个用户
 
通过Eclipse如何能够连接数据库
windows菜单下references—MyEclipse——Database Explorer——database drivers--- 
 DB Browser
  new
  连接mysql或者oracle数据库
  

Eclipse如何能够支持hibernate
 选中工程----myEclipse---add hibernate capacity
 从数据库中选中表,Hibernate reverse engineering
  反向工程
  src
  是否生成映射文件、pojo
  Hibernate.cfg.xml
  HibernateSessionFactory

需要封装什么样的方法呢?
 登录和注册
  注册主要是插入一个用户 
  登录,我们要把用户名和密码给他,并且登录成功后,我们要把其信息放到session里面
  

<%@page pageEncoding="utf-8"%>
 在eclipse中一读取到该信息,则会自动地将该页面以utf-8方式
 
<%@page pageEncoding="utf-8"%>
<html xmlns="http://www.w3.org/1999/xhtml">
 <head>
  <title></title>
  <link rel="stylesheet" type="text/css" href="css/style.css" />
 </head>
 <body>
  <div id="wrap">
   <div id="top_content">
    <%@include file="header.jsp"%>
    <div id="content">
     <p id="whereami">
     </p>
     <h1>
      注册
     </h1>
     <form action="register.jsp" method="post">
      <table cellpadding="0" cellspacing="0" border="0"
       class="form_table">
       <tr>
        <td valign="middle" align="right">
         用户名:
        </td>
        <td valign="middle" align="left">
         <input type="text" class="inputgri" name="username" />
        </td>
       </tr>
       <tr>
        <td valign="middle" align="right">
         真实姓名:
        </td>
        <td valign="middle" align="left">
         <input type="text" class="inputgri" name="name" />
        </td>
       </tr>
       <tr>
        <td valign="middle" align="right">
         密码:
        </td>
        <td valign="middle" align="left">
         <input type="password" class="inputgri" name="pwd" />
        </td>
       </tr>
       <tr>
        <td valign="middle" align="right">
         性别:
        </td>
        <td valign="middle" align="left">
         男
         <input type="radio" class="inputgri" name="sex" value="m" checked="checked"/>
         女
         <input type="radio" class="inputgri" name="sex" value="f"/>
        </td>
       </tr>
       
       <tr>
        <td valign="middle" align="right">
         验证码:
         <img id="num" src="image" />
         <a href="javascript:;" onclick="document.getElementById('num').src = 'image?'+(new Date()).getTime()">换一张</a>
         ==================================================================
                   // 欺骗服务器
       //重点部分:?????
       //img id="num"
       //
        </td>
        <td valign="middle" align="left">
         <input type="text" class="inputgri" name="number" />
        </td>
       </tr>
      </table>
      <p>
       <input type="submit" class="button" value="Submit &raquo;" />
      </p>
     </form>
    </div>
   </div>
   <%@include file="foot.jsp"%>
  </div>
 </body>
</html>
<a href="#">换一张</a>刷新本页
<a href="http://.....">换一张</a>连接到某地址
<a href="JavaScript:alter("abc")">换一张</a>
<a href="JavaScript:;" onclick="document.getElementById('num').src='image?'+(new Date()).getTime()">换一张</a>
这句话是在浏览器中运行,不是在服务器端运行
其中document.getElementById是获得 image这个元素.src是改这个属性;new Date()是javascript里面的date而非java中的date
为什么呢?如果浏览器在某个时刻发现页面上某个地方变了会重新向新地址发请求
<img src="image">
<img src="image?17272772727">
服务器收到信息后,会以为?后面是参数,但是又是一个错误的参数。。访问的还是原来的地址
相当于欺骗服务器
 

如何将表单的数据一下子灌到user类对应的表中
<%@page import="org.whatisjava.dao.*" %>
<%@page import="org.whatisjava.domain.*" %>
<%@page import="java.util.*" %>
<%@page import="org.apache.commons.beanutils.*" %>
<%
//请求提交过来首先要判断下验证码是否准确
//提交的表单里面的数据是什么?
String number1=request.getParameter("number");
String number2=(String)session.getAttribute("number");
if (number2!=null && number2.equals(number1)){
 UserDao dao=new UserDao();
 User user=new User();
 //user.setUsername(request.getParameter("username"));
 //.....
 //这样的语句会写一大串,由于request里面的都是文本内容,可能还存在强转之类语句
 //一般情况下,一项项来写的话,编程特别多,有没有一种方式或方法一下子把数据
  //全部灌到user里面呢
  //可以采用commons特殊组件  commons-beansUtils组件
 //BeanUtils.;
 Map map=request.getParameterMap();
 BeanUtils.populate(user, map);//把map数组填充到user里面,在填充的时候已经把类型转换好了。
 //用户提交了一个user{},map就做成数组了。
 //user {aaa}
 //password {bbb}
 //lanaguage(checkbox){a,b,c,abc} //对应多个值
 
 //能够实现这种填充的是关键是:哪一个表单名字应该知道user的哪一个属性。
 //最好的就是把表单中的名字和user的set和get方法的名字相同即可
 
 dao.addUser(user);
 
 response.sendRedirect("login_form.jsp");
 
  
 //System.out.println(map);//在控制台上打印出map
 
}else {
 response.sendRedirect("register_form.jsp");
 
}
 
%>
 
 
 

hibernate 映射文件
 类的getXxxxx,setXxxx方法来进行的映射