实验八 JSP内置对象(二)
需要相关资料的,详见文章末尾,免费自提
一、实验目的:
1、掌握session的基本用法。
2、理解各类域对象的区别。
二、 实验内容:
实现基于验证码的用户登录。
【实验步骤】(补全代码一 ~ 代码七
)
(1)新建一个名为”web8”的项目(Web应用程序)。在项目中,新建JSP,命名为“login”。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>login</title>
<script>
function _change() {
//获取<img>元素
var imgEle = document.getElementById("vCode");
imgEle.src = "<%=request.getContextPath()%>/checkCodeServlet?"+new Date().getTime();
//因为某些浏览器会对src缓存,所以需要添加不同的参数,保证每次的URL参数都不同
}
</script>
<style>
div{
color: red;
}
</style>
</head>
<body>
<form action="<%= request.getContextPath()%>/login" method="post">
<table>
<tr>
<td>用户名</td><td><input type="text" name="username"></td></tr>
<tr>
<td>密码</td><td><input type="password" name="userpass"></td>
<td><div><%=request.getAttribute("login_error") == null ? "" : request.getAttribute("login_error")%></div></td></tr>
<tr>
<td>验证码</td><td><input type="text" name="checkCode"></td>
<td><div><%= request.getAttribute("code_error") == null ? "" : request.getAttribute("code_error")%></div></td></tr>
<tr>
<td colspan="2">
<img id="vCode" src="<%=request.getContextPath()%>/checkCodeServlet">
<a href="javascript:_change()">看不清,换一张</a>
</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="登录">
<input type="reset" value="重置">
</td>
</tr>
</table>
</form>
</body>
</html>
(2)新建java包“it.servlet”。在该包中新建java类,命名为“CheckCodeServlet”。
CheckCodeServlet.java的主要功能:生成验证码,将验证码显示在浏览器中,并将验证码存储于session对象。
package it.servlet;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
@WebServlet("/checkCodeServlet")
public class CheckCodeServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
int width = 100;
int height = 40;
//创建验证码图片对象
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
//美化图片
//1.填充背景色
Graphics g = image.getGraphics();
g.setColor(Color.blue);
g.fillRect(0, 0, width, height);
//2.画边框
g.setColor(Color.CYAN);
g.drawRect(0, 0, width - 1, height - 1);
//3.写验证码
//验证码的字符
String str = "ABCDEFGHIGKLMNOPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz0123456789";
//生成随机字符串
Random ran = new Random();
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= 4; i++) {
int index = ran.nextInt(str.length());
char ch = str.charAt(index);//随机字符
sb.append(ch);
g.setFont(new Font("TimesRoman", Font.PLAIN, 16));
g.drawString(ch + "", width / 5 * i, height / 2);
}
String checkCode_session = sb.toString();
//【代码一】将验证码存入session,属性名为checkCode_session
//4.画干扰线
g.setColor(Color.green);
//随机生成坐标点
for (int i = 1; i <= 10; i++) {
int x1 = ran.nextInt(width);
int x2 = ran.nextInt(width);
int y1 = ran.nextInt(height);
int y2 = ran.nextInt(height);
g.drawLine(x1, y1, x2, y2);
}
//将图片输出到页面展示
ImageIO.write(image, "jpg", /*【代码二】*/);
}
}
(3)在“it.servlet”包中新建名为“LoginServlet”的Java类。LoginServlet.java用于检查用户名、密码以及验证码是否正确:登录成功,跳转到welcome.jsp;登录失败,跳转回login.jsp,并显示相应的错误提示。
package it.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//【代码三】设置请求体的编码
//获取参数
String username = req.getParameter("username");
String password = req.getParameter("userpass");
String checkCode = req.getParameter("checkCode");
//【代码四】获取生成的验证码
//先判断验证码是否正确,忽略大小写比较
if (checkCode_session != null && checkCode_session.equalsIgnoreCase(checkCode)) {
if ("张三".equals(username) && "123".equals(password)) {
//【代码五】登录成功,存储用户名到session,并重定向到welcome.jsp
} else {
//【代码六】登录失败,存储提示信息“用户名或密码错误”到request,
// 并转发到login.jsp
}
} else {
//验证码不一致,存储提示信息到request
req.setAttribute("code_error", "验证码错误");
//转发到登录页面
req.getRequestDispatcher("/login.jsp").forward(req, resp);
}
}
}
(4)新建JSP文件,命名为“welcome“。
welcome.jsp检查用户是否登录成功;如果没有登录,则跳转回login.jsp;否则显示欢迎信息“***,欢迎您”,效果如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<style>
span{
color:red;
font-weight: bold
}
</style>
</head>
<body>
<%--【代码七】--%>
</body>
</html>
具体实现
package it.servlet;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
@WebServlet("/checkCodeServlet")
public class CheckCodeServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
int width = 100;
int height = 40;
//创建验证码图片对象
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
//美化图片
//1.填充背景色
Graphics g = image.getGraphics();
g.setColor(Color.blue);
g.fillRect(0, 0, width, height);
//2.画边框
g.setColor(Color.CYAN);
g.drawRect(0, 0, width - 1, height - 1);
//3.写验证码
//验证码的字符
String str = "ABCDEFGHIGKLMNOPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz0123456789";
//生成随机字符串
Random ran = new Random();
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= 4; i++) {
int index = ran.nextInt(str.length());
char ch = str.charAt(index);//随机字符
sb.append(ch);
g.setFont(new Font("TimesRoman", Font.PLAIN, 16));
g.drawString(ch + "", width / 5 * i, height / 2);
}
String checkCode_session = sb.toString();
//【代码一】将验证码存入session,属性名为checkCode_session
HttpSession session = req.getSession();
session.setAttribute("checkCode_session",checkCode_session);
//4.画干扰线
g.setColor(Color.green);
//随机生成坐标点
for (int i = 1; i <= 10; i++) {
int x1 = ran.nextInt(width);
int x2 = ran.nextInt(width);
int y1 = ran.nextInt(height);
int y2 = ran.nextInt(height);
g.drawLine(x1, y1, x2, y2);
}
ImageIO.setUseCache(false); //禁用图像缓存的设置 由于个人原因验证码无法显示
//将图片输出到页面展示
ImageIO.write(image, "jpg", resp.getOutputStream()/*【代码二】*/);
}
}
package it.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//【代码三】设置请求体的编码
req.setCharacterEncoding("UTF-8");
//获取参数
String username = req.getParameter("username");
String password = req.getParameter("userpass");
String checkCode = req.getParameter("checkCode");
//【代码四】获取生成的验证码
HttpSession session = req.getSession();
String checkCode_session = (String) session.getAttribute("checkCode_session");//返回的是object
//先判断验证码是否正确,忽略大小写比较
if (checkCode_session != null && checkCode_session.equalsIgnoreCase(checkCode)) {
if ("张三".equals(username) && "123".equals(password)) {
//【代码五】登录成功,存储用户名到session,并重定向到welcome.jsp
HttpSession userSession= req.getSession();
userSession.setAttribute("username",username);
resp.sendRedirect(req.getContextPath() + "/welcome.jsp");
} else {
//【代码六】登录失败,存储提示信息“用户名或密码错误”到request,
// 并转发到login.jsp
req.setAttribute("error_message","用户名或密码错误");
req.getRequestDispatcher("/login.jsp").forward(req,resp);
}
} else {
//验证码不一致,存储提示信息到request
req.setAttribute("code_error", "验证码错误");
//转发到登录页面
req.getRequestDispatcher("/login.jsp").forward(req, resp);
}
}
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<style>
span{
color:red;
font-weight: bold
}
</style>
</head>
<body>
<%--【代码七】--%>
<%
// 从 session 中获取用户名
String username = (String) session.getAttribute("username");
// 检查用户是否登录
if (username == null) {
// 用户未登录,重定向到登录页面
response.sendRedirect(request.getContextPath() + "/login.jsp");
} else {
%>
<span><%= username %></span>,欢迎您!
<%
}
%>
</body>
</html>
报错解决
1、若出现login.jsp页面的验证码不显示的问题
HTTP状态 500 - 内部服务器错误
类型 异常报告
消息 Can't create output stream!
描述 服务器遇到一个意外的情况,阻止它完成请求。
例外情况
javax.imageio.IIOException: Can't create output stream!
javax.imageio.ImageIO.write(ImageIO.java:1574)
com.neuedu.his.controller.CheckCodeServlet.doPost(CheckCodeServlet.java:85)
com.neuedu.his.controller.CheckCodeServlet.doGet(CheckCodeServlet.java:89)
javax.servlet.http.HttpServlet.service(HttpServlet.java:626)
javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
com.neuedu.his.filter.LoginFilter.doFilter(LoginFilter.java:57)
com.neuedu.his.filter.CharsetFilter.doFilter(CharsetFilter.java:37)
com.neuedu.his.filter.Filter1.doFilter(Filter1.java:29)
根本原因。
javax.imageio.IIOException: Can't create cache file!
javax.imageio.ImageIO.createImageOutputStream(ImageIO.java:423)
javax.imageio.ImageIO.write(ImageIO.java:1572)
com.neuedu.his.controller.CheckCodeServlet.doPost(CheckCodeServlet.java:85)
com.neuedu.his.controller.CheckCodeServlet.doGet(CheckCodeServlet.java:89)
javax.servlet.http.HttpServlet.service(HttpServlet.java:626)
javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
com.neuedu.his.filter.LoginFilter.doFilter(LoginFilter.java:57)
com.neuedu.his.filter.CharsetFilter.doFilter(CharsetFilter.java:37)
com.neuedu.his.filter.Filter1.doFilter(Filter1.java:29)
根本原因。
java.nio.file.AccessDeniedException: D:\Program Files\apache\apache-tomcat-8.5.60\temp\imageio8447768555205008617.tmp
sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:83)
sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97)
sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102)
sun.nio.fs.WindowsFileSystemProvider.newByteChannel(WindowsFileSystemProvider.java:230)
java.nio.file.Files.newByteChannel(Files.java:361)
java.nio.file.Files.createFile(Files.java:632)
java.nio.file.TempFileHelper.create(TempFileHelper.java:138)
java.nio.file.TempFileHelper.createTempFile(TempFileHelper.java:161)
java.nio.file.Files.createTempFile(Files.java:897)
javax.imageio.stream.FileCacheImageOutputStream.<init>(FileCacheImageOutputStream.java:88)
com.sun.imageio.spi.OutputStreamImageOutputStreamSpi.createOutputStreamInstance(OutputStreamImageOutputStreamSpi.java:68)
javax.imageio.ImageIO.createImageOutputStream(ImageIO.java:419)
javax.imageio.ImageIO.write(ImageIO.java:1572)
com.neuedu.his.controller.CheckCodeServlet.doPost(CheckCodeServlet.java:85)
com.neuedu.his.controller.CheckCodeServlet.doGet(CheckCodeServlet.java:89)
javax.servlet.http.HttpServlet.service(HttpServlet.java:626)
javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
com.neuedu.his.filter.LoginFilter.doFilter(LoginFilter.java:57)
com.neuedu.his.filter.CharsetFilter.doFilter(CharsetFilter.java:37)
com.neuedu.his.filter.Filter1.doFilter(Filter1.java:29)
):注意 主要问题的全部 stack 信息可以在 server logs 里查看
Apache Tomcat/9.0.38
没有办法创建输出流
没有办法创建缓冲文件
没有办法在D:\Program Files\apache\apache-tomcat-8.5.60\temp目录生成imageio8447768555205008617.tmp文件
可能原因:
1、tomcat目录下没有temp文件,没有这个文件夹自然无法存放缓存文件,因为默认的是存放在这个文件夹。
2、ImageIO默认是true,使用缓存目录,不使用文件目录缓存,使用内存缓存。
解决方案
1.在tomcat文件夹里创建个temp文件夹
2.在CheckCodeServlet类中ImageIO.write(image, "jpg", resp.getOutputStream()/*【代码二】*/); //前添加ImageIO.setUseCache(false);语句
ImageIO.setUseCache(false);
ImageIO.write(image, "jpg", resp.getOutputStream()/*【代码二】*/);
资料自提(若过期,请留言)
链接:https://pan.baidu.com/s/1nQvEeV-GNvBdPkH_Ah4wFQ?pwd=m114
提取码:m114