一、验证码组件
这里使用的验证码组件是kaptcha验证码开源项目。
kaptcha是一个简单好用的验证码生成工具,通过配置,可以自己定义验证码大小、颜色、显示的字符等等。下面就来讲一下如何使用kaptcha生成验证码以及在服务器端取出验证码进行校验。
我们用eclipse 的jsp-servlet项目,使用的tomcat服务器,来展示一下kaptcha的用法。
(一)导入jar包,配置映射路径
1、我们可以到Maven 网站中,找到kaptcha的jar包。放到WEB-INF的lib目录下,右键 buil path -> add to build path
2、配置映射路径
使用<servlet>和<servlet-mapping>
元素在web.xml配置文件kaptcha的映射
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>hotel</display-name>
<!-- 配置kaptcha的映射路径 -->
<servlet>
<!-- 配置其,servlet-name,自行取名 -->
<servlet-name>k</servlet-name>
<!-- Kaptcha类的全名,包名+类名 -->
<servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
</servlet>
<servlet-mapping>
<!-- 与上面的servlet-name必须一致 -->
<servlet-name>k</servlet-name>
<!-- 设置映射路径,后面我们就是通过这个url来访问kaptcha的 -->
<url-pattern>/kap</url-pattern>
</servlet-mapping>
</web-app>
kaptcha的映射路径与servlet的映射路径的配置很类似,可以去查看我另外一篇博客servlet基础,servlet的映射路径。
3、还可以在web.xml文件中,配置kaptcha的其他配置
例如:
<!-- 部分web.xml -->
<servlet>
<servlet-name>Kaptcha</servlet-name>
<servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
<!-- 配置图片的宽度参数,为200px -->
<init-param>
<!-- 参数名称 -->
<param-name>kaptcha.image.width</param-name>
<!-- 参数值,该参数的默认值为200 -->
<param-value>200</param-value>
<!-- 参数描述,可以不写 -->
<description>Width in pixels of the kaptcha image.</description>
</init-param>
</servlet>
更多的验证码 KAPTCHA 参数:
Constant | 描述 | 默认值 |
kaptcha.border | 图片边框,合法值:yes , no | yes |
kaptcha.border.color | 边框颜色,合法值: r,g,b (and optional alpha) 或者 white,black,blue. | black |
kaptcha.border.thickness | 边框厚度,合法值:>0 | 1 |
kaptcha.image.width | 图片宽 | 200 |
kaptcha.image.height | 图片高 | 50 |
kaptcha.producer.impl | 图片实现类 | com.google.code.kaptcha.impl.DefaultKaptcha |
kaptcha.textproducer.impl | 文本实现类 | com.google.code.kaptcha.text.impl.DefaultTextCreator |
kaptcha.textproducer.char.string | 文本集合,验证码值从此集合中获取 | abcde2345678gfynmnpwx |
kaptcha.textproducer.char.length | 验证码长度 | 5 |
kaptcha.textproducer.font.names | 字体 | Arial, Courier |
kaptcha.textproducer.font.size | 字体大小 | 40px |
kaptcha.textproducer.font.color | 字体颜色,合法值: r,g,b 或者 white,black,blue. | black |
kaptcha.textproducer.char.space | 文字间隔 | 2 |
kaptcha.noise.impl | 干扰实现类 | com.google.code.kaptcha.impl.DefaultNoise |
kaptcha.noise.color | 干扰颜色,合法值: r,g,b 或者 white,black,blue. | black |
kaptcha.obscurificator.impl | 图片样式: 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy | com.google.code.kaptcha.impl.WaterRipple |
kaptcha.background.impl | 背景实现类 | com.google.code.kaptcha.impl.DefaultBackground |
kaptcha.background.clear.from | 背景颜色渐变,开始颜色 | light grey |
kaptcha.background.clear.to | 背景颜色渐变,结束颜色 | white |
kaptcha.word.impl | 文字渲染器 | com.google.code.kaptcha.text.impl.DefaultWordRenderer |
kaptcha.session.key | session key | KAPTCHA_SESSION_KEY |
kaptcha.session.date | session date | KAPTCHA_SESSION_DATE |
(二)在web页面中调用kaptcha组件
这里用到ajax,jquery,javascript技术,可以到我的另外一篇博客查看。
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>demo</title>
</head>
<!-- 导入jquery包 -->
<script src="js/jquery-3.2.1.js"></script>
<body>
<form id="form1" onsubmit="return false">
<div>
<!-- 显示验证码
要注意隔着img的src属性,就是我们刚才配置的kaptcha的映射路径
-->
<img id="img1" src="kap" width="100px" style="position: relative;top: 8px">
<!-- 用户输入验证码的输入框 -->
<input id="i1" style="width:80px;margin-left:10px;" name="kaptcha" type="text" />
<!-- href属性也可以用 javascript:click() 来触发事件更换验证码。我们这里用的jquery -->
<a id="a1" href="#" style="font-size:5px;text-decoration:none">换一个</a>
</div><br>
<!--
如果为ajax异步提交,button的type属性设置为button。
如果为submit会引发普通表单提交,导致整个页面刷新
-->
<button type="button" id="b1" >提交</button>
</form><span id="span1" style="font-size:5px;color:red;flow:right" ></span>
</body>
<script>
//给a标签注册一个click事件,用作 触发更换验证码的
$("#a1").click(function(){
//通过更改img元素的src属性,来实现
//为了防止浏览器对于同于url使用缓存,因此在src后面添加一个不断变化的时间参数
$("#img1").attr("src","kap?time="+new Date().getTime());
})
//给button 按钮注册一个点击事件,用作提交用户输入的验证码给服务器
$("#b1").click(function(){
//获取 用户输入的内容
if($("#i1").val()==""){
//假如用户输入的验证码为空
$("#span1").html("请输入验证码");
}else{
//将用户输入的验证码提交到服务器
$.ajax({
//设置url
url:"KaptchaServlet?time="+new Date().getTime(),
//将表单序列化为字符串方便ajax提交
data:$("#form1").serialize(),
//当ajax提交成功的时候,调用该方法,并将服务器的相应放在date这个参数中
success:function(data){
//当ajax提交成功的时候,将span元素的改为服务器响应的数据,验证码是否正确
$("#span1").html(data);
}
});
}
});
</script>
</html>
(三)在servlet中验证验证码是否正确
package servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.code.kaptcha.*;
/**
* Servlet implementation class KaptchaServlet
*/
@WebServlet("/KaptchaServlet")
public class KaptchaServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
//kaptcha随即生成的验证码
String kaptchaExpected = (String)request.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY);
//获取用户输入的验证码
String kaptchaReceived = request.getParameter("kaptcha");
String str ;
//判断两个验证是否相等
if(kaptchaExpected.equals(kaptchaReceived)){
str = "验证码输入正确";
}else
str = "验证码输入不正确";
//服务器将判断信息发送给浏览器
PrintWriter p = response.getWriter();
p.write(str);
p.flush();
p.close();
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
二、上传下载组件
在Web应用系统开发中,文件上传和下载功能是非常常用的功能。实现文件上传功能,需完成如下二步操作:
- 1、在web页面中添加上传输入项
- 2、在servlet中读取上传文件的数据,并保存到本地硬盘中
<!-- 1、在web页面中添加上传输入项
1、<input type=“file”>标签用于在web页面中添加文件上传输入项,须要设置input输入项的name属性,否则浏览器将不会发送上传文件的数据。
3、必须把form的
enctype属值设为multipart/form-data,
method属性设置为post方式
设置该值后,浏览器在上传文件时,将把文件数据附带在http请求消息体中,并使用MIME协议对上传的文件进行描述,以方便接收方对上传数据进行解析和处理。
-->
<form action="Test" method="post" enctype="multipart/form-data">
<input name="username" type="text"/>
<input name="file" type="file"/><br>
<input type="submit" />
</form>
那么如何在servlet获取上传文件的数据呢?我们可以使用手动上传,和使用组件上传。
(一)手动上传
实际上,获取上传文件数据就是request.getInputStream方法而已。但是其获取的是整个请求的实体内容。
//在servlet获取上传文件的数据
//获取request的输入流
BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream()));
//将数据输出到控制条中
String str = null;
while((str=reader.readLine())!=null){
System.out.println(str);
}
例如,我们上传一个图片。获得的请求实体内容是。
------WebKitFormBoundary7KkkwAtzBQzDAkRb--
------WebKitFormBoundaryaMCZF5oFRXcYHuN8
Content-Disposition: form-data; name="username"
hh
------WebKitFormBoundaryaMCZF5oFRXcYHuN8
Content-Disposition: form-data; name="file"; filename="xml涓枃涔辩爜闂.png"
Content-Type: image/png
//。。。无数的二进制代码
对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用Servlet获取上传文件的输入流然后再解析里面的的内容是不实际的。
-
使用别人写好的组件进行上传,这些组件会帮我们分析请求的实体内容,将各个请求参数封装在一个类里面,让我们来获取。常用的上传组件有:
-
commonupload组件
cos 组件
这里我们使用commonupload上传组件。
(二)使用组件上传
使用Commons-fileupload组件实现文件上传,需要导入该组件相应的支撑jar包:Commons-fileupload和commons-io。可以在这里找得到..
导入jar包后,我们就可以使用了。
package servlet;
import java.io.File;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
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;
/**
* Description:
* 实现文件的上传
*
* @author lee
*/
@WebServlet("/Test")
public class Test extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//由于表单设置为文件上表单,因此调用request.getParameter是得不到参数
//需要,组件替我们去分析请求的实体内容
//设置编码
response.setContentType("text/html;charset:=utf-8");
request.setCharacterEncoding("utf-8");
//创建文件上传工厂类
DiskFileItemFactory fac = new DiskFileItemFactory();
//创建文件上传核心类对象
ServletFileUpload upload = new ServletFileUpload(fac);
//判断当前表单是否为文件文件上传表单
if(ServletFileUpload.isMultipartContent(request)){
try{
@SuppressWarnings("unchecked")
//获取所有的表单提交的参数
List<FileItem> list = upload.parseRequest(request);
//遍历
for(FileItem item:list){
//当参数为普通的参数,就可以直接用getString方法,获取其用户输入的值
if(item.isFormField()){
//1、普通表单
String fileName = item.getFieldName();//文本框名字
String value = item.getString(); //文本框的值
System.out.println(fileName+","+value);
}else{
//2、但参数为文件
String fileName = item.getFieldName();//文本框名字
//upload这里文件夹需要配置映射路径
//将文件输出在指定的文件夹当中,实现项目与文件分离
File file = new File("D:/file",fileName);
item.write(file);
//从内存中删除文件
item.delete();
}
}
}catch(Exception e){
e.printStackTrace();
}
}else{
System.out.println("不是文件上传");
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
实验一下,结果是正确的。
(三)基于Servlet3.0的上传
在以前的servlet版本中实现文件上传,一般都需要借助第三方开源组件。在Servlet3.0中提供了对文件上传的原生支持,我们不需要借助任何第三方上传组件,只要在servlet中加上@MultipartConfig 注解,直接使用Servlet3.0提供的API就能够实现文件上传功能了。
package servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
/**
* Description:
* 使用servlet3.0新特性实现文件上传
*
*/
@MultipartConfig
@WebServlet("/Test1")
public class Test1 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置编码格式
response.setContentType("text/html;charset=utf-8");
//1、获取普通的表单提交的参数
//在之前servlet版本中,表单类型为文件上传类型,是不能直接使用getparameter方法获取请求参数的
String userName = request.getParameter("username");
System.out.println(userName);
//2、获取指定的文件上传。需要传入的参数就是文件上传的input元素中的name属性的值
Part part = request.getPart("file");
//在请求头中,获取上传文件的名字
String str = part.getHeader("Content-DisPosition");
String fileName = str.substring(str.indexOf("filename")+10,str.lastIndexOf("\""));
//将文件保存在硬盘中
part.write("C:/Users/lenovopc/Desktop/"+fileName);
part.delete();
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
doGet(request, response);
}
}
(四)文件下载
1、设置Content-Type 的值为:application/x-msdownload
Web 服务器需要告诉浏览器其所输出的内容的类型不是普通的文本文件或 HTML 文件,而是一个要保存到本地的下载文件。
2、设置 Content-Disposition 报头,该报头指定了接收程序处理数据内容的方式。
(1)在 HTTP 应用中只有 attachment 是标准方式,attachment 表示要求用户干预。
(2)在 attachment 后面还可以指定 filename 参数,该参数是服务器建议浏览器将实体内容保存到文件中的文件名称。
注意:要在设置 Content-Dispostion 之前一定要指定 Content-Type
response.setContentType("application/x-msdownload");
//防止出现中文编码问题,可以指定编码进行编译
String str = "attachment;filename="+URLEncoder.encode(fileName,"utf-8");
response.setHeader("Content-Disposition",str);
1、直接用 <a>
标签来作为一般文件的下载
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>demo</title>
</head>
<body>
<!-- 1、一种方法是直接用a标签,直指目标文件 -->
<a href="login.jsp">通过超链接下载</a>
<!-- 2、一种是提交给servlet,让servlet响应请求,返回目标文件 -->
<a href="Test2">通过servlet下载</a>
</body>
</html>
2、通过Servlet进行操作,输出下载内容
package servlet;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class Test2
*/
@WebServlet("/Test2")
public class Test2 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//现在随便找了一个文件,拿到它的名字和绝对路径
String fileName = "login.jsp";
//获取目标文件的绝对路径
String fullName = request.getServletContext().getRealPath("login.jsp");
response.setContentType("application/x-msdownload");
//防止出现中文编码问题,可以指定编码进行编译
String str = "attachment;filename="+URLEncoder.encode(fileName,"utf-8");
response.setHeader("Content-Disposition",str);
//使用输入流读取文件
InputStream in = new FileInputStream(fullName);
//获取响应输出流
OutputStream out = response.getOutputStream();
//输出
int b;
while((b=in.read())!=-1){
out.write(b);
}
//关闭流
in.close();
out.close();
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
(五)ajax异步上传文件
这里需要,导入 jquery和ajaxfileupload 的js文件。关于jQuery和ajax的知识可以看我另外一篇博客。
异步上传图片,实际上是通过ajax异步提交,将文件提交给servlet处理。然后serlvet处理后,返回保存图片的uri。然后,通过ajax的回调函数function success,获取到servlet返回的uri。将指定的img标签的src属性,设置为uri,就能在页面中显示图片了。
jsp页面:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>异步上传图片</title>
<!-- 引入js文件 -->
<script src="js/jquery-3.2.1.js" type="text/javascript"></script>
<script src="js/ajaxfileupload.js" type="text/javascript"></script>
</head>
<body>
<h3>使用 ajaxFileUpload工具异步上传图片</h3>
<p><input type="file" id="file1" name="file" onchange="ajaxFileUpload()"/></p>
<!-- 显示异步上传图片 -->
<p><img id="img1" height="100px" src="" /></p>
<hr>
<h3>使用 FormData类包装表单,异步上传图片</h3>
<form id="form" enctype="multipart/form-data">
<input type="file" id="file2" name="file" onchange="ajaxFile()" />
</form>
<!-- 显示异步上传图片 -->
<p><img id="img2" height="100px" src="" /></p>
</body>
</body>
<script type="text/javascript">
//1、使用 ajaxFileUpload工具异步上传图片
function ajaxFileUpload() {
$.ajaxFileUpload
({
url: 'FileUpload', //用于文件上传的服务器端请求地址
secureuri: false, //是否需要安全协议,一般设置为false
fileElementId: 'file1', //文件上传域的ID
dataType: 'json', //返回值类型 一般设置为json
success: function (data) //服务器成功响应处理函数
{
//alert(data);
$("#img1").attr("src", data);
},
error: function (data)//服务器响应失败处理函数
{
alert("上传失败!");
}
})
return false;
}
//2、 使用 FormData类包装表单,异步上传图片
function ajaxFile(){
/*
通过FormData对象可以组装一组用 XMLHttpRequest发送请求的键/值对。
它可以更灵活方便的发送表单数据,因为可以独立于表单使用。
如果你把表单的编码类型设置为multipart/form-data ,
则通过FormData传输的数据格式和表单通过submit() 方法传输的数据格式相同.
*/
var formData = new FormData(document.getElementById("form"));
$.ajax({
url:"FileUpload",
type:"post",
data: formData,
dataType:"json",
/*
在 multipart/form-data 后面有boundary以及一串字符,这是分界符,后面的一堆字符串是随机生成的,
目的是防止上传文件中出现分界符导致服务器无法正确识别文件起始位置。
在 ajax 中 contentType 设置为 false 是为了避免 JQuery 对其操作,
从而失去分界符,而使服务器不能正常解析文件。
*/
contentType: false,
/*
processData
(默认: true) 默认情况下,通过data选项传递进来的数据,如果是一个对象(技术上讲只要不是字符串),
都会处理转化成一个查询字符串,以配合默认内容类型 "application/x-www-form-urlencoded"。
如果要发送 DOM 树信息或其它不希望转换的信息,请设置为 false。
*/
processData: false,
success: function (data) //服务器成功响应处理函数
{
//alert(data);
$("#img2").attr("src", data);
}
})
}
</script>
</html>
服务端处理:
package org.demo.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.UUID;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import com.google.gson.Gson;
/**
* Servlet implementation class FileUpload
*/
@WebServlet("/FileUpload")
@MultipartConfig
public class FileUpload extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("?");
//利用servlet3.0来获取异步提交的图片
Part img = request.getPart("file");
//System.out.println(img.getSubmittedFileName()+" "+img.getName());
//获取图片类型
String fileName = img.getSubmittedFileName();
String fileType = fileName.substring(fileName.indexOf("."),fileName.length());
//给图片以UUID命名一个唯一的名字
String imgName = UUID.randomUUID().toString()+fileType;
//保存到指定的路径
String imgUrl = "C:/Users/lenovopc/workspace/Ademo/WebContent/image/" + imgName;
img.write(imgUrl);
//将图片相对路径(需要通过tomcat的server.xml配置映射路径)转化成json格式
Gson gson = new Gson();
String gsonStr = gson.toJson("image/"+imgName);
//输出 图片的相对路径 ,然后页面就可以根据该路径获取图片了
PrintWriter pw = response.getWriter();
pw.write(gsonStr);
pw.close();
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
}
结果如下:
(六)本地预览图片文件
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>jQuery本地预览图片</title>
<!-- 引入jquery -->
<script src="js/jquery-3.2.1.js"></script>
</head>
<body>
<p><input type="file" id="file" /></p>
<img src="" id="img1" width="100px"/>
</body>
<script>
$("#file").change(function(){
//调用window.URL.createObjectURL获取该图片的uri
var fileURI = window.URL.createObjectURL(this.files[0]);
//alert(fileURI);
$("#img1").prop("src",fileURI);
})
</script>
</html>
##三、在线编辑组件
##四、JavaMail组件