10、JavaEE---验证码、文件的上传与下载

目录

验证码开发-认识验证码

验证码的作用

验证码原理 

验证码必须满足的几个条件 

 验证码工作流程

 开发验证码

在 JSP 上开发验证码步骤如下 

 如何嵌入验证码(前端代码)

 怎样刷新验证码

 用验证码进行验证

如何实现文件上传

Web开发中的文件上传步骤 

1、基于Servlet的文件上传(Servlet 3.0)

Servlet文件上传操作步骤:

 文件上传的表单设置(前端代码)

2、@MultipartConfig注解

 Part接口

单文件上传:

 根据Part对象获取文件名

案例:单文件上传

多文件上传:

案例:多文件上传

Part接口常用方法

基于Servlet的文件上传

 文件的下载

使用超链接实现文件下载

使用程序编码实现下载

案例:文件下载

文件名乱码问题

如何出现保存对话框 

  查询分页

 分页处理的重要性

分页策略

 基于缓冲的分页

查询时分页 


验证码开发-认识验证码

验证码的作用

有了验证码,可以避免上述的问题

原因:每登录一次服务器,客户都需要提供一次验证码,而验证码每次都是不同的。所以很难使用机器人程序反复登录,因为机器人程序无法识别验证码。这就是验证码强大的功能所在。

验证码原理 

所谓验证码,就是由服务器产生的一串随机数字或符号,形成一幅图片,图片应该传给客户端,为了防止客户端用一些程序来进行自动识别,图片中通常要加上一些干扰象素,由用户肉眼识别其中的验证码信息。客户输入表单提交时,验证码也提交给网站服务器,只有验证成功,才能执行后续操作。

验证码必须满足的几个条件 

  • 不同的请求,得到的验证码应该是随机的,必须由服务器端产生;
  • 验证码必须通过人眼识别,而通过图像编程的方法编写的机器人程序在客户端运行,几乎无法识别;
  • 除了人眼观察之外,客户端无法通过其他手段获取验证码信息。

 验证码工作流程

不同的请求,得到的验证码应该是随机的,必须由服务器端产生;

 开发验证码

在 JSP 上开发验证码步骤如下 

1、实例化 java.awt.image.BufferedImage 类。

它的作用是访问图像数据缓冲区,或者说对所要绘的图片对象进行访问

BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

 2、从BufferedImange 中获取 Graphics 类对象(画笔),并设定相关属性:

Graphics g = image.getGraphics(); 

Graphics 提供了对几何形状、坐标转换、颜色管理和文本布局更为复杂的控制。

g.setColor(Color color);	//设置颜色 
g.fillRect(int,int,int,int);	//设置生成的图片为长方形

3、产生随机数,并将其存入 session 中

Random rnd = new Random(); 
int randNum = rnd.nextInt(8999) + 1000; 
String randStr = String.valueOf(randNum); 
session.setAttribute("randStr", randStr);

4、用画笔画出随机数和干扰点

g.setColor(Color.black); 
g.setFont(new Font("", Font.PLAIN, 20)); 
g.drawString(randStr, 10, 17); 
//随机产生 100 个干扰点,使图象中的验证码不易被其他程序探测到 
for (int i = 0; i < 100; i++){	
    int x = rnd.nextInt(width); 
    int y = rnd.nextInt(height); 
    g.drawOval(x, y, 1, 1); 
}

 5、输出图象到页面

ImageIO.write(Image image, "JPEG", 
response.getOutputStream()); 

 6、清除缓冲区

out.clear(); 
out = pageContext.pushBody(); 

 如何嵌入验证码(前端代码)

表单中嵌入如下代码:

验证码:<input type="text" name="code" size="10">
<!-- 将验证码当成图片处理 -->
<img border=0 src="code.jsp"><BR>

 怎样刷新验证码

一般使用 JavaScript 刷新验证码,最方便的方法是:点击验证码图片,获得新的验证码。请参见refresh.jsp 部分代码:

<script type="text/javascript">		
function refresh(){			
	loginForm.imgValidate.src =encodeURI("code.jsp?id="+new Date());	
}	
</script>
……
请输入验证码:
<input type="text" name="code" size="10">
<img name="imgValidate" src="code.jsp" onclick="refresh()">

 用验证码进行验证

具体代码示例见ValidateServlet.java

//得到提交的验证码
String code = request.getParameter("code");
//获取session中的验证码
HttpSession session = request.getSession();
String randStr = (String)session.getAttribute("randStr");
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
if(!code.equals(randStr)){
	out.println("验证码错误!");
} else {
	out.println("验证码正确!跳转到LoginServlet......");
}		

如何实现文件上传

文件上传的本质,其实就是把客户端本地计算机的文件保存到网站服务器中,当然,此时不能简单用request.getParameter()方法来获得文件的数据。

Web开发中的文件上传步骤 

1. 在Web页面中添加上传输入项;  

 2. 在Servlet中读取上传文件的数据,并保存到本地硬盘。

1、基于Servlet的文件上传(Servlet 3.0)

Servlet3.0提供了对文件上传的直接支持,使用简单。

Servlet文件上传操作步骤:

  • 给Servlet添加@MultipartConfig注解;
  • 从HttpServletRequest对象获取Part文件对象;
  • 调用HttpServletRequest对象getHeader("content-disposition")方法获取文件名信息;
  • 调用Part对象的write方法将文件上传到指定路径。

 文件上传的表单设置(前端代码)

<form action="upload" method="post" enctype="multipart/form-data" >
	<input type="file" name="file1">
	<input type=“submit” value=“文件上传">
</form>

若未指明enctype值,则默认以application/x-www-form-urlencoded为编码方式提交表单字段(非文件上传)。

若指明了enctype值为multipart/form-data,则进行文件上传。

2、@MultipartConfig注解

@MultipartConfig注解主要是为了辅助Servlet中HttpServletRequest提供对上传文件的支持。

该注解标注在Servlet上面,以表示该Servlet希望处理请求的MIME类型是 multipart/form-data。

该注解的常用属性如下表所示。

属性名 

类型 

描 述 

location 

String 

指定上传文件存放的目录。

maxFileSize 

long

指定上传文件的最大值,单位是字节。默认值为-1,表示没有限制。 

maxRequestSize 

long

指定上传文件的个数,应用在多文件上传。默认值为-1,表示没有限制。

当指定了location后,在调用Part的write(String fileName)方法把文件写入到磁盘的时候,文件名称可以不用带路径,但是如果fileName带了绝对路径,那将以fileName所带路径为准把文件写入磁盘。

 Part接口

每个文件用一个javax.servlet.http.Part对象来表示。

单文件上传:

调用HttpServletRequest对象getPart(String name)方法获得Part文件对象。其中,参数name为文件域的名称。

如:

Part photo = request.getPart("resPath");

 根据Part对象获取文件名

Servlet规范中不提供获取上传文件名的方法,需通过Part对象调用getHeader("content-disposition")方法间接获取。

public static String getFileName(Part part){
    if(part == null)
return null;
     //fileName形式为:form-data; name="resPath"; filename="sise.jpg"
     String fileName = part.getHeader("content-disposition");
     //没有选择文件
     if(fileName.lastIndexOf("=") + 2 == fileName.length() - 1)
           return null;
     return fileName.substring(fileName.lastIndexOf("=") + 2, fileName.length() - 1);
}

案例:单文件上传

 uploadHttpOne.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="uploadHttpOneServlet" method="post" enctype="multipart/form-data">
    <table>

        <tr>
            <td>文件描述</td>
            <td><input type="text" name="filediscription"></td>
        </tr>
        <tr>
            <td>请选择文件</td>
            <td><input type="file" name="resPath"></td>
        </tr>
        <tr>
            <td align="right"><input type="reset" value="重填"></td>
            <td><input type="submit" value="上传"></td>
        </tr>
    </table>

</form>
</body>
</html>

UploadHttpOneServlet

package servlet;

import jakarta.servlet.*;
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.*;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import util.MyUtil;

@WebServlet(name = "UploadHttpOneServlet", value = "/UploadHttpOneServlet")
@MultipartConfig(maxFileSize = 10*1024*1024) //设置上传文件的最大值10MB
public class UploadHttpOneServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request,response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置响应的内容类型
        response.setContentType("text/html;charset=utf-8");
        //取得输出对象
        PrintWriter out=response.getWriter();
        request.setCharacterEncoding("utf-8");
        //获取Part对象
        Part part=request.getPart("resPath");
        String filediscription=request.getParameter("filediscription");
        out.println("输入的文件描述:"+filediscription+"<br>");
        //指定上传的文件保存到服务器的uploadFiles目录中
        File uploadFileDir =new File(getServletContext().getRealPath("/uolpadFiles"));
        if(!uploadFileDir.exists()){
            uploadFileDir.mkdir();
        }
        //获取原始文件名
        String oldName=MyUtil.getFileName(part);
        out.println("上传文件的原名:"+oldName+"<br>");
        out.println("上传文件的大小:"+part.getSize()+"<br>");
        if(oldName!=null){
            //上传到服务器的uploadFiles目录中
            part.write(uploadFileDir+File.separator+oldName);
        }
        out.println("文件上传到:"+uploadFileDir+File.separator+oldName+"<br>");
    }
}

多文件上传:

调用HttpServletRequest对象getParts()方法获得Part文件对象集合。

如:

Collection<Part> photos = request.getParts();

案例:多文件上传

 uploadHttpMulti.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="UploadHttpMultiServlet" method="post" enctype="multipart/form-data">
  <table>

    <tr>
      <td>文件1描述</td>
      <td><input type="text" name="filediscription1"></td>
    </tr>
    <tr>
      <td>请选择文件1:</td>
      <td><input type="file" name="resPath1"></td>
    </tr>
    <tr>
      <td>文件2描述</td>
      <td><input type="text" name="filediscription2"></td>
    </tr>
    <tr>
      <td>请选择文件2:</td>
      <td><input type="file" name="resPath2"></td>
    </tr>
    <tr>
      <td align="right"><input type="reset" value="重填"></td>
      <td><input type="submit" value="上传"></td>
    </tr>
  </table>

</form>
</body>
</html>

 UploadHttpMultiServlet

package servlet;

import jakarta.servlet.*;
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.*;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;

@WebServlet(name = "UploadHttpMultiServlet", value = "/UploadHttpMultiServlet")
@MultipartConfig
public class UploadHttpMultiServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request,response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置响应的内容类型
        response.setContentType("text/html;charset=utf-8");
        //取得输出对象
        PrintWriter out=response.getWriter();
        request.setCharacterEncoding("utf-8");
        String filediscription1=request.getParameter("filediscription1");
        out.println("输入的文件1描述:"+filediscription1+"<br>");
        String filediscription2=request.getParameter("filediscription2");
        out.println("输入的文件2描述:"+filediscription2+"<br>");
        //指定上传的文件保存到服务器的uploadFiles目录中
        File uploadFileDir =new File(getServletContext().getRealPath("/uolpadFiles"));
        if(!uploadFileDir.exists()){
            uploadFileDir.mkdir();
        }
        //获得Part集合
        Collection<Part> parts=request.getParts();
        for(Part part:parts){
            //没有选择文件或不是文件域
            if(part==null || !part.getName().contains("resPath")){
                continue;
            }
            
        //获取原始文件名
        String oldName=MyUtil.getFileName(part);
        out.println("上传文件的原名:"+oldName+"<br>");
        out.println("上传文件的大小:"+part.getSize()+"<br>");
        if(oldName!=null){
            //上传到服务器的uploadFiles目录中
            part.write(uploadFileDir+File.separator+oldName);
        }
        out.println("文件上传到:"+uploadFileDir+File.separator+oldName+"<br>");
    }
    }
}

Part接口常用方法

方法

功能

void delete()

删除任何相关的临时磁盘文件

String getContentType()

获得客户端浏览器设置的文件数据项的MIME类型

String getHeader(String name) 

获得指定的part头的一个字符串。

例如:getHeader("content-disposition")

返回form-data; name="xxx"; filename="xxx"

InputStream getInputStream( )

获得一个输入流,通过它来读取文件的内容

String getName( )

获得表单文件域的名称

long getSize( )

获得文件的大小

void write(String fileName)

将文件上传到fileName指定的目录里

基于Servlet的文件上传

 文件的下载

使用超链接实现文件下载

<a href="/down/test.doc">下载test.doc</a>

超链接实现下载固然简单,但暴露了下载文件的真实位置,并且只能下载存放在 Web应用程序所在的目录下的文件。 

使用程序编码实现下载

只需将按钮所在表单提交到该文件,或提交到Servlet,让该Servlet跳转到文件即可。

利用程序编码实现下载,可以增加安全访问控制,还可以从任意位置提供下载的数据,可以将文件存放到 Web 应用程序以外的目录中,也可以将文件保存到数据库中。

利用程序实现下载需要设置两个报头:
1、Web服务器需要告诉浏览器其所输出内容的类型不是普通文本文件或 HTML文件,而是一个要保存到本地的下载文件设置 Content-Type 的值为 application/x-msdownload.

2、 Web 服务器希望浏览器不直接处理相应的实体内容,而是由用户选择将相应的实体内容保存到一个文件中,这需要设置Content-Disposition 报头。该报头指定了接收程序处理数据内容的方式,在HTTP应用中只有 attachment 是标准方式,attachment 表示要求用户干预。在attachment后面还可以指定filename 参数,该参数是服务器建议浏览器将实体内容保存到文件中的文件名称。
        设置报头的示例如下:

response.setHeader("Content-Type", "application/x-msdownload");
response.setHeader("Content-Disposition", "attachment;filename="+filename);

案例:文件下载

该实例要求:首先将 10.1 节上传到服务器 upoadFiles 目录中的文件列举到页面,然后单击页面中的下载链接下载文件。具体步骤如下。

编写列举被下载文件的Servlet-----ShowDownServlet.java

package servlet;

import jakarta.servlet.*;
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.*;

import java.io.File;
import java.io.IOException;

@WebServlet(name = "ShowDownServlet", value = "/ShowDownServlet")
public class ShowDownServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //指定从服务器的uploadFiles目录下在文件
        File downLoadFileDir=new File(getServletContext().getRealPath("/uploadFiles"));
        //获取目录文件
        File[] list=downLoadFileDir.listFiles();
        request.setAttribute("fileList",list);
        RequestDispatcher dis=request.getRequestDispatcher("showInfo.jsp");
        dis.forward(request,response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request,response);
    }
}

编写文件显示页面一showInfo.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<table border="1">
  <tr bgcolor="LightGreen">
    <th>文件名称</th>
    <th>下载课件</th>
  </tr>
  <c:forEach var="afile" items="${fileList}">
    <tr>
      <%--afile.name相当于file.getName()--%>
      <td align="center"><a href="downloadServlet?resPath=${afile.name}" style="text-decoration: none">下载</a></td>

    </tr>
  </c:forEach>
</table>
</body>
</html>

编写下载Servlet-----DownloadServlet.java 

package servlet;

import jakarta.servlet.*;
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.*;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

@WebServlet(name = "DownloadServlet", value = "/DownloadServlet")
public class DownloadServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request,response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //要下载的文件路径
        File downLoadFileDir=new File(getServletContext().getRealPath("/uploadFiles"));
        FileInputStream in =null;//输入流
        ServletOutputStream out =null; //输出流
        try{
            aFileName=request.getParameter("resPath");
            //设置下载文件使用的报头
            response.setHeader("Content-Type","application/x-msddownload");
            //MyUtil.toUTF8String(aFileName)解决下载文件名中中文字符乱码问题
            response.setHeader("Content-Disposition","attachment;filename="+MyUtil.toUTF8String(aFileName));
            //读入文件
            in =new FileInputStream(downLoadFileDir+File.separator+aFileName);
            //得到相应对象的输出流,用于向客户输出二进制数据
            out=response.getOutputStream();
            out.flush();
            int aRead=0;
            byte b[]=new byte[1024];
            while((aRead=in.read(b))!=-1 & in !=null){
                out.write(b,0,aRead);

            }
            out.flush();
            in.close();
            out.close();
        }catch (Throwable e){
            e.printStackTrace();
        }
    }
}

文件名乱码问题

 如果下载的文件名中有中文字符,浏览器提示保存的文件名将显示为乱码。要解决这个乱码问题,需要对下载的文件名按照UTF-8进行编码。首先,在本章工具类MyUtil中添加一个静态字符编码转换方法,代码如下:

package util;

import java.io.UnsupportedEncodingException;

public class MyUtil {

    public static String toUTF8String(String str){
        StringBuffer sb = new StringBuffer();
        int len=str.length();
        for(int i=0; i<len;i++){
            //取出字符中的每个字符
            char c =str.charAt(i);
            //Unicode码值为0~255,不做处理
            if(c>=0 && c<=255){
                sb.append(c);
            }else {
                //转换为UTF-8编码
                byte b[];
                try{
                    b=Character.toString(c).getBytes("UTF-8");

                }catch (UnsupportedEncodingException e){
                    e.printStackTrace();
                    b=null;
                }
                //转换为%HH的字符串形式
                for(int j=0;j<b.length;j++){
                    int k=b[j];
                    if (k<0){
                        k &= 255;
                    }
                    sb.append("%"+Integer.toHexString(k).toUpperCase());
                }
            }
        }
        return sb.toString();
    }
}

如何出现保存对话框 

步骤:

  1. 让链接或按钮提交到Servlet或JSP;
  2. 在Servlet或JSP中设置Header属性或ContentType属性,让Servlet或JSP 跳转到下载的文件。
// 设置下载文件使用的报头
response.setHeader("Content-Type", "application/x-msdownload");
//告诉客户端出现下载框,并指定下载框中的文件名
response.setHeader("Content-Disposition","attachment;filename="+filename);  
//指定下载文件
RequestDispatcher rd = request.getRequestDispatcher("/FILES/" + filename);
rd.forward(request, response);

  查询分页

 分页处理的重要性

需要展示的数据量很大时,分页处理就成为了一个重要选项

分页策略

1、基于缓存的分页:一次性把用户查询的全部记录查询出来,放在session或其它缓存机制中,之后根据用户需要数据,从中选取,然后显示。

优点:访问数据库次数少 缺点:占用内存资源多。

2、基于查询的分页:利用有关数据库的子句来限制结果集的大小每次只取出一页数据进行显示,翻页时重新访问数据库,取出当页数据。

优点:能访问最新数据    缺点:数据访问太频繁。

 基于缓冲的分页

 指标与功能:总页数、首页、末页、上一页、下一页,并具有随意跳到任一页的功能

总页数计算

设N为总记录数,M为每页显示的记录数

如果N能整除M,则总页数=N/M;    

若N不能整除M,则总页数=N/M+1;

某一页显示的记录范围:

若规定记录的序号从0开始,第i页显示记录的序号为:     (i-1)*M<=序号<i*M    

查询时分页 

MySQL 语句:

SELECT * FROM t_student ORDER BY stuno LIMIT "+(currentPageIndex-1)*countPerPage + "," +countPerPage;

limit是mysql的语法

select * from table limit m,n  

//显示从索引号为m 开始的n 条记录(第一条记录的索引号为0)

StudentDao.java:queryPage()查询当前页的学生集合;

PageServelet2.java:得到当前页的学生集合,得到总页数等,并存入sesssion中:

showStudent2.jsp:显示输出。    

==================================================================

实践项目:lab08

验证码的开发与使用:

lab08--login.jsp、loginServlet

文件上传相关操作

addBook.jsp、AddBookServlet

查询分页

 bookList.jsp、ShowAllBooksServlet

图盘下载

 DownloadServlet、bookList.jsp

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值