实现一个简单的用户登录验证程序,如果用户名是 abc ,密码是 123,则显示欢迎用户的信息,否则显示“用户名或密码不正确”。
【分析】 该案例采用 JSP 页面只完成提交信息和验证结果的显示,而验证过程由 Servlet 完成,这些组件通过 request (或 HttpServletRequest)对象实现数据共享。由提交页面将数据传递给 Servlet,而 Servlet 获取数据并实现验证,根据验证结果,转向显示验证结果的页面。
【设计】 根据分析,该系统需要设计3个组件以及修改 web.xml 文件。
(1)登录表单页面: login.jsp。
(2)处理登录请求并实现验证的 Servlet:LoginCheckServlet.java。
(3)显示提示的页面: Info.jsp。
(4)修改 web.xml,配置 Servlet的信息。
假设,表单传递的参数为 username 和 userpwd。
1.登录表单页面login.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登录页面</title>
</head>
<body>
<form action="CheckServlet" method="post">
<table>
<tr align="center">
<td>请输入用户名:<input type="text" name="username" size="20">
</td>
</tr>
<tr align="center">
<td>请输入密码: <input type="password" name="userpwd"
size="20">
</td>
</tr align="center">
<td><input type="submit" value="登录" /> <input type="reset" /></td>
</tr>
</table>
</form>
</body>
</html>
2.处理登录的 Servlet:LoginCheckServlet.java
package servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
public class LoginCheckServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String userName = request.getParameter("username");
String userPwd = request.getParameter("userpwd");
String info = "";
if(("abc".equals(userName))&&"123".equals(userPwd)){
info = "欢迎你"+userName+"!";
}else{
info = "用户名或密码不正确!";
}
request.setAttribute("outputMessage", info);
request.getRequestDispatcher("/info.jsp").forward(request,response);
}
}
3.显示提示的页面 info.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title heretitle>
head>
<body>
<%=request.getAttribute("outputMessage") %>
body>
html>
4.修改配置文件,在 web.xml 中,修改LoginCheckServlet 的配置信息:
注意:与前面的表单action路径一致
5.运行效果图
输入正确的用户名和密码
输入错误的用户名和密码
1.前端的登陆页面如下:login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="login" method="post">
姓名:<input name="name" type="text"><br><br>
密码:<input name="password" type="password"><br><br>
<input name="vericode" placeholder="验证码" value="" style="width: 60px">
<img id="vericodeImg" src="imageCode">
<a id="kanbuq" href="javascript:changeImg();">看不清,换一张</a><br><br>
<input type="submit" value="提交">
</form>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script type="text/javascript">
function changeImg() {
//需要让每次请求的url都发生变化。否则服务器会认为访问的时一张图片,就不会刷新请求了
//每次url一样,服务器会认为访问的url是同一张图片,没变化啊
$("#vericodeImg").attr("src","imageCode?"+Math.random())
}
</script>
</body>
</html>
2.后端的LoginServlet登陆实现逻辑如下:LoginServlet.java
映射的url-patten: /login
package servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf8");
String name=request.getParameter("name");
String password=request.getParameter("password");
String vericode=request.getParameter("vericode");
String generatedCode= (String) request.getSession().getAttribute("verityCode");
if (name.equals("bob")&&password.equals("123")&&vericode.toLowerCase().equals(generatedCode.toLowerCase())){
response.getWriter().write("登录成功");
}else {response.getWriter().write("登录失败");}
}
}
3.下面是两个工具代码:生成验证码字符串CreateVerificationCode.java
package bean;
import java.util.Arrays;
public class CreateVerificationCode {
/**
* 验证码难度级别
*/
public enum SecurityCodeLevel {
Simple,
Medium,
Hard
}
public static String getSecurityCode() {
return (String) getSecurityCode(4, SecurityCodeLevel.Medium, false);
}
public static String getSecurityCode(int length, SecurityCodeLevel level, boolean isCanRepeat) {
int len = length;
//除去容易混淆的0和o,1和l
char[] codes = {
'1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
'j', 'm', 'n', 'p', 'q', 'r', 's', 't','u',
'v', 'w', 'x', 'y', 'z','A','B','C','D','E',
'F','G','H','J','K','L','M','N','P','Q','R','S',
'T','U','V','W','X','Y','Z'};
if(level==SecurityCodeLevel.Simple){
codes= Arrays.copyOfRange(codes,0,9);
}else if (level==SecurityCodeLevel.Medium){
codes= Arrays.copyOfRange(codes,0,33);
}
int n=codes.length;
//抛出运行时异常
if (len>n&&isCanRepeat==false){
throw new RuntimeException(
String.format("调用securitycode.getSecurityCode(%1$s,len,level,isCanRepeat,n)"));}
char[] result=new char[len];
//判断能否出现重复的字符
if (isCanRepeat){
for(int i=0;i<result.length;i++){
//索引0 and n-1
int r=(int)(Math.random()*n);
//将result中的第i个元素设为codes[r]存放的数值
result[i]=codes[r];
}
}else {
for (int i=0;i<result.length;i++){
int r=(int)(Math.random()*n);
//将result中的第i个元素设为codes[r]存放的数值
result[i]=codes[r];
codes[r]=codes[n-1];
n--;
}
}
return String.valueOf(result);
}
}
4.生成验证码图片(它是基于生成验证码字符串类的)CreateVerificationCodeImage.java
package bean;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Random;
/**
* 可生成数字,大写,小写字母及三者混合类型的验证码,支持自定义干扰线,图文颜色
*/
public class CreateVerificationCodeImage {
private String securityCode;
public CreateVerificationCodeImage(String securityCode){
this.securityCode=securityCode;
}
//高度
private static final int CAPTCHA_HEIGHT = 35;
//宽度
private static final int CAPTCHA_WIDTH = 100;
//数字的长度
//private static final int NUMBER_CNT = 6;
private Random r = new Random();
// 字体
private String[] fontNames = { "宋体", "华文楷体", "黑体", "华文新魏", "华文隶书", "微软雅黑", "楷体_GB2312" };
//private String[] fontNames = { "宋体", "黑体", "微软雅黑"};
/**
* 机能概要:生成随机的颜色
* @return
*/
private Color randomColor() {
int red = r.nextInt(150);
int green = r.nextInt(150);
int blue = r.nextInt(150);
return new Color(red, green, blue);
}
/**
* 机能概要:生成随机的字体
* @return
*/
private Font randomFont() {
int index = r.nextInt(fontNames.length);
String fontName = fontNames[index];// 生成随机的字体名称
int style = r.nextInt(4);// 生成随机的样式, 0(无样式), 1(粗体), 2(斜体), 3(粗体+斜体)
int size = r.nextInt(5) + 24; // 生成随机字号, 24 ~ 28
// int size = r.nextInt(5) + 15; // 生成随机字号, 20 ~ 24
return new Font(fontName, style, size);
}
// 画干扰线
private void drawLine(BufferedImage image) {
int num = 5;// 一共画5条
Graphics2D g2 = (Graphics2D) image.getGraphics();
for (int i = 0; i < num; i++) {// 生成两个点的坐标,即4个值
int x1 = r.nextInt(CAPTCHA_WIDTH);
int y1 = r.nextInt(CAPTCHA_HEIGHT);
int x2 = r.nextInt(CAPTCHA_WIDTH);
int y2 = r.nextInt(CAPTCHA_HEIGHT);
g2.setStroke(new BasicStroke(1.5F));
g2.setColor(randomColor()); // 随机生成干扰线颜色
g2.drawLine(x1, y1, x2, y2);// 画线
}
}
// 创建BufferedImage,生成图片
public BufferedImage createImage() {
BufferedImage image = new BufferedImage(CAPTCHA_WIDTH, CAPTCHA_HEIGHT, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = (Graphics2D) image.getGraphics();
// 背景色,白色
g2.setColor(new Color(255, 255, 255));
g2.fillRect(0, 0, CAPTCHA_WIDTH, CAPTCHA_HEIGHT);
// 向图片中画4个字符 String securityCode
for (int i = 0; i < securityCode.length(); i++) {// 循环四次,每次生成一个字符
String s = securityCode.charAt(i) + "";// 随机生成一个字母
// float x = i * 1.0F * CAPTCHA_WIDTH / NUMBER_CNT; // 设置当前字符的x轴坐标
float x = i * 1.0F * CAPTCHA_WIDTH / 4+7F; // 设置当前字符的x轴坐标
g2.setFont(randomFont()); // 设置随机字体
g2.setColor(randomColor()); // 设置随机颜色
g2.drawString(s, x, CAPTCHA_HEIGHT-7); // 画图,依次将字符写入到图片的相应位置-------------------
}
drawLine(image); // 添加干扰线
return image;
}
}
5)调用工具类的生成验证码图片的方法,在通过response对象,将图片流返回给前端,有img标签的src属性负责解析:ImageCodeServelt.java
映射的url-patten: /imageCode
package servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;
import javax.imageio.ImageIO;
import bean.CreateVerificationCode;
import bean.CreateVerificationCodeImage;
public class ImageCodeServelt extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String vericode= CreateVerificationCode.getSecurityCode();
HttpSession session=request.getSession();
session.setAttribute("verityCode",vericode);
//设置返回的内容
response.setContentType("img/jpeg");
//浏览器不缓存响应内容--验证码图片,点一次就要刷新一次,所以不能有缓存出现
response.setHeader("Pragma","No-cache");
response.setHeader("Cache-Control","no-cache");
//设置验证码失效时间
response.setDateHeader("Expires",0);
//以字节流发过去,交给img的src属性去解析即可
ImageIO.write(new CreateVerificationCodeImage(vericode).createImage(),"JPEG",response.getOutputStream());
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}