zoukankan      html  css  js  c++  java
  • JavaWeb--Cookie和Session小练习(完善版)

    一、前言

    本篇博客完善自Cookie和Session小练习

    在上一篇博客中的案例以及能够实现:

    1、成功登录后才能访问相关资源、

    2、第一次登录之后不需要输入用户名

    但其实在我们登录页面的操作还不够完善,还需要加上验证码。

    所以本篇博客实现添加图片验证码功能来完善之前的案例。

    二、需求分析

    (一)之前的流程图

    (二)验证码功能流程图大致如下

    (三)各部分功能如下

    login.jsp:(有增加)

    新增:获取图片验证码(点击换一张则获取新验证码)
    1、提供登录表单
    2、表单提交至loginServlet
    3、如果身份验证失败,需要显示错误信息
    4、如果是因为直接访问从而跳转到登录页面,也需要显示错误信息
    5、第一次登录之后不需要输入用户名
    

    VerifyServlet:(新创建,和loginServlet同一目录)

    1、生成验证码图片
    2、将验证码文本值保存到session域
    3、将验证码图片返回给登录页面
    

    loginServlet:(有增加)

    新增:先对验证码进行判断,正确在进行后续判断;否则结束
    1、需要处理乱码问题
    2、获取用户信息
    3、对用户信息进行验证
    4、如果验证成功:
    	a、在cookie中保存用户信息
    	b、在session域保存用户信息,并且显示指定页面
    5、如果验证失败:
    	a、在request域中设置错误信息,并且跳转到登录页面
    

    succ1.jsp:无增加

    succ2.jsp:无增加

    三、代码实现

    login.jsp:

    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>	<%-- 导包 --%>
    <%@ page import="java.net.URLDecoder" %>
    <%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
    %>
    
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
        <base href="<%=basePath%>">
        
        <title>My JSP 'login.jsp' starting page</title>
        
    	<meta http-equiv="pragma" content="no-cache">
    	<meta http-equiv="cache-control" content="no-cache">
    	<meta http-equiv="expires" content="0">    
    	<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    	<meta http-equiv="description" content="This is my page">
    	<!--
    	<link rel="stylesheet" type="text/css" href="styles.css">
    	-->
    
      </head>
      
      <body>
     	<h1>登录</h1>
     	<%-- 显示错误信息 --%>
     	<%
     		String msg = "";
     		String str = (String)request.getAttribute("msg");
     		if(str != null){
     			msg = str;
     		}
     	%>
     	<font color="red"><b><%= msg %></b></font>
     	
     	<%-- 登录时,可以从cookie中获取用户名 --%>
     	<%	
     		String userName="";
     		Cookie[] cs = request.getCookies();	//遍历cookie所有cookie的值,查看是否有键为userName的cookie、
     		if(cs != null){
     			for(Cookie c:cs){
     				if("userName".equals(c.getName())){//有键为userName的cookie、
     					userName = URLDecoder.decode(c.getValue(), "utf-8");
     					break;
     				}
     			}
     		}
     	%>
     	
     	<%-- 提供表单 --%>
        <form action="/day11_3/LoginServlet" method="post">
        	用户名:<input type="text" name="userName" value="<%= userName %>"/><br/><br/>
        	密    码:<input type="password" name="pwd"/><br/><br/>
        	验证码:<input type="text" name="verifyCode" size="3"/>
        		  <img id="image" src="/day11_4/VerifyServlet"/>
        		  <a href="javascript:_change()">换一张</a><br/><br/>
        	<input type="submit" value="登录"/> 
        </form>
      </body>
      
      <script type="text/javascript">
      function _change(){
      	/*
      	1、获取img标签
      	2、每次点击换一次张时,修改其src属性,从而重新请求(加上时间参数解决缓存问题)
      	*/
      	var imageEle = document.getElementById("image");
      	imageEle.src = "/day11_3/VerifyServlet?a="+new Date().getTime();
      }
      </script>
    </html>
    

    VerifyServlet:

    package com.zuobiao.login;
    
    import java.awt.image.BufferedImage;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    /**
     * 2020年4月14日12:16:28
     * 用来生成验证码的Servlet
     * @author ASUS
     *
     */
    public class VerifyServlet extends HttpServlet {
    
    	public void doGet(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    		/**
    		 * 1、生成验证码图片
    		 * 2、将验证码文本值保存到session域
    		 * 3、将图片响应给登录页面
    		 */
    		VerifyCode vc = new VerifyCode();	//获取验证码生成器
    		BufferedImage image = vc.getImage();	//获取生成的验证码
    		
    		request.getSession().setAttribute("session_verifyCode", vc.getText()); //将验证码文本保存到session
    		
    		VerifyCode.output(image, response.getOutputStream());	//将验证码图片响应到浏览器
    	}
    }
    

    loginServlet:

    package com.zuobiao.login;
    import java.io.IOException;
    import java.net.URLEncoder;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.Cookie;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    
    public class LoginServlet extends HttpServlet {
    
    	public void doPost(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    		/**
    		 * 增加:判断验证码是否错误
    		 * 1、处理乱码问题
    		 * 2、获取请求参数
    		 * 3、进行用户信息校验
    		 * 	4、正确
    		 * 		a、保存cookie,内容为用户名
    		 * 		b、在session中加入用户信息,然后重定向到succ1.jsp
    		 * 	5、如果错误,则在request域中设置错误信息,然后转发到login.jsp重新登录,并显示错误信息
    		 */
    		request.setCharacterEncoding("UTF-8");
    		
    		/**
    		 * 增加部分:
    		 * 1、获取传递过来的验证码参数:verifyCode
    		 * 2、获取session域中的验证码文本值
    		 * 3、判断两者是否相等
    		 */
    		String verifyCode = request.getParameter("verifyCode");
    		String session_verifyCode = (String) request.getSession().getAttribute("session_verifyCode");
    		
    		if(!session_verifyCode.equalsIgnoreCase(verifyCode)){	//如果验证码不相等,则在request域中设置错误信息,并转发到登录页面
    			request.setAttribute("msg", "验证码输入错误!");
    			request.getRequestDispatcher("/session2/login.jsp").forward(request, response);
    			return;	//此处一定要记得返回,否则还是会继续运行下去
    		}
    		
    		String userName = request.getParameter("userName");
    		String pwd = request.getParameter("pwd");
    		
    		boolean noNull = (userName!=null)&(pwd!=null);	//用户名和密码不为空
    		boolean flag1 = "张三".equals(userName);			//用户名正确
    		boolean flag2 = "123456".equals(pwd);			//密码正确
    		boolean coorect = flag1&flag2;
    		
    		if(noNull&coorect){	 //验证成功
    			//保存cookie
    			Cookie cookie = new Cookie("userName", URLEncoder.encode(userName, "utf-8"));
    			cookie.setMaxAge(60*60*24);
    			response.addCookie(cookie);
    			
    			//获取session,然后添加用户信息
    			HttpSession session = request.getSession();
    			session.setAttribute("userName", userName);
    			//重定向到succ1
    			response.sendRedirect("/day11_3/session2/succ1.jsp");
    		}else{	//验证失败
    			//在request域中添加错误信息
    			request.setAttribute("msg", "用户名或密码输入错误!");
    			//转发到login.jsp
    			request.getRequestDispatcher("/session2/login.jsp").forward(request, response);
    		}
    	}
    }
    

    四、测试结果

    1、登录页面:

    2、登录成功:

    3、验证码错误导致登陆失败:

    五、需要注意的地方

    生成验证码的代码是使用的封装好的工具类,如下:

    VerifyCode:

    package com.zuobiao.login;
    
    import java.awt.BasicStroke;
    import java.awt.Color;
    import java.awt.Font;
    import java.awt.Graphics2D;
    import java.awt.image.BufferedImage;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.util.Random;
    
    import javax.imageio.ImageIO;
    
    public class VerifyCode {
    	private int w = 70;
    	private int h = 35;
     	private Random r = new Random();
     	// {"宋体", "华文楷体", "黑体", "华文新魏", "华文隶书", "微软雅黑", "楷体_GB2312"}
    	private String[] fontNames  = {"宋体", "华文楷体", "黑体", "微软雅黑", "楷体_GB2312"};
    	// 可选字符
    	private String codes  = "23456789abcdefghjkmnopqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ";
    	// 背景色
    	private Color bgColor  = new Color(255, 255, 255);
    	// 验证码上的文本
    	private String text ;
    	
    	// 生成随机的颜色
    	private Color randomColor () {
    		int red = r.nextInt(150);
    		int green = r.nextInt(150);
    		int blue = r.nextInt(150);
    		return new Color(red, green, blue);
    	}
    	
    	// 生成随机的字体
    	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
    		return new Font(fontName, style, size);
    	}
    	
    	// 画干扰线
    	private void drawLine (BufferedImage image) {
    		int num  = 3;//一共画3条
    		Graphics2D g2 = (Graphics2D)image.getGraphics();
    		for(int i = 0; i < num; i++) {//生成两个点的坐标,即4个值
    			int x1 = r.nextInt(w);
    			int y1 = r.nextInt(h);
    			int x2 = r.nextInt(w);
    			int y2 = r.nextInt(h); 
    			g2.setStroke(new BasicStroke(1.5F)); 
    			g2.setColor(Color.BLUE); //干扰线是蓝色
    			g2.drawLine(x1, y1, x2, y2);//画线
    		}
    	}
    	
    	// 随机生成一个字符
    	private char randomChar () {
    		int index = r.nextInt(codes.length());
    		return codes.charAt(index);
    	}
    	
    	// 创建BufferedImage
    	private BufferedImage createImage () {
    		BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); 
    		Graphics2D g2 = (Graphics2D)image.getGraphics(); 
    		g2.setColor(this.bgColor);
    		g2.fillRect(0, 0, w, h);
     		return image;
    	}
    	
    	// 调用这个方法得到验证码
    	public BufferedImage getImage () {
    		BufferedImage image = createImage();//创建图片缓冲区 
    		Graphics2D g2 = (Graphics2D)image.getGraphics();//得到绘制环境
    		StringBuilder sb = new StringBuilder();//用来装载生成的验证码文本
    		// 向图片中画4个字符
    		for(int i = 0; i < 4; i++)  {//循环四次,每次生成一个字符
    			String s = randomChar() + "";//随机生成一个字母 
    			sb.append(s); //把字母添加到sb中
    			float x = i * 1.0F * w / 4; //设置当前字符的x轴坐标
    			g2.setFont(randomFont()); //设置随机字体
    			g2.setColor(randomColor()); //设置随机颜色
    			g2.drawString(s, x, h-5); //画图
    		}
    		this.text = sb.toString(); //把生成的字符串赋给了this.text
    		drawLine(image); //添加干扰线
    		return image;		
    	}
    	
    	// 返回验证码图片上的文本
    	public String getText () {
    		return text;
    	}
    	
    	// 保存图片到指定的输出流
    	public static void output (BufferedImage image, OutputStream out) 
    				throws IOException {
    		ImageIO.write(image, "JPEG", out);
    	}
    }
    

    Java新手,若有错误,欢迎指正!

  • 相关阅读:
    CodeForces gym Nasta Rabbara lct
    bzoj 4025 二分图 lct
    CodeForces 785E Anton and Permutation
    bzoj 3669 魔法森林
    模板汇总——快读 fread
    bzoj2049 Cave 洞穴勘测 lct
    bzoj 2002 弹飞绵羊 lct裸题
    HDU 6394 Tree 分块 || lct
    HDU 6364 Ringland
    nyoj221_Tree_subsequent_traversal
  • 原文地址:https://www.cnblogs.com/Java-biao/p/12724886.html
Copyright © 2011-2022 走看看