Java web 登录加验证码案例

Java web 登录加验证码案例

2020/8/25
在上次的登录案例中加入验证码的处理和使用jsp进行操作
需求

  1. 访问带有验证码的登录页面login.jsp
  2. 用户输入用户名,密码以及验证码。
  • 如果用户名和密码输入有误,跳转登录页面,提示:用户名或密码错误
  • 如果验证码输入有误,跳转登录页面,提示:验证码错误
  • 如果全部输入正确,则跳转到主页success.jsp,显示:用户名,欢迎您

1.绘制验证码(servlet)

在上次的验证码的基础上对验证码进行了细节上的操作,使背景填充随机颜色,字符的高度随机位置,干扰线的随机颜色
代码如下

package zsc.Servlet.Check;

import javax.imageio.ImageIO;
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 javax.servlet.http.HttpSession;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Random;

/***
 * 验证码的servlet
 */
@WebServlet("/CheckDemo1")
public class CheckDemo1 extends HttpServlet {
    
    
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
        //获取随机颜色的内部类
        class color{
    
    
            public Color getcolor(){
    
    
                Random ra=new Random();
                int r = ra.nextInt(256);
                int g = ra.nextInt(256);
                int b = ra.nextInt(256);
                return new Color(r,g,b);
            }
        }
        //1.创建一个内存中的图片对象
        int width=100;
        int height=50;
        BufferedImage image=new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
        //2.绘画图片(要先填充颜色再画边框,这样边框才会显示)
                //1.获取画笔对象
                Graphics g=image.getGraphics();
                //2.填充随机颜色(使用color内部类的getcolor方法)
                g.setColor(new color().getcolor());
                g.fillRect(0,0,width,height);
                //3.画边框
                g.setColor(Color.BLUE);
                g.drawRect(0,0,width-1,height-1);
                //4.画入验证码
                String str="qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0123456789";
                Random ran=new Random();
                String ss="";           //该字符串用于存储验证码的值
                for (int i = 0; i < 4; i++) {
    
    
                    //取随机字符
                    int index = ran.nextInt(str.length());
                    char c = str.charAt(index);
                    //取随机画字符的高度范围为20-40,int s = random.nextInt(max)%(max-min+1) + min;
                    int h = ran.nextInt(40)%(40-20+1)+20;
                    //设置画笔画字符的字体大小和画笔颜色
                    Font font=new Font("宋体", Font.ITALIC,30);
                    g.setFont(font);
                    g.setColor(Color.white);
                    g.drawString(c+"",width/6*(i+1),h);
                    ss=ss+c;
                }

                    System.out.println(ss);

                //5.将验证码的值存入会话作用域
                HttpSession session = request.getSession();
                session.setAttribute("check",ss);
                //6.画随机的干扰线
                for (int i = 0; i < 10; i++) {
    
    
                    //设置画笔颜色(随机色)
                    g.setColor(new color().getcolor());
                    //2.设置干扰线的宽度(使用Graphics2D类的setStroke方法)
                    Graphics2D g2d= (Graphics2D) g;
                    g2d.setStroke(new BasicStroke(1.5f));
                    //取随机的干扰线的两点
                    int x1 = ran.nextInt(width);
                    int y1 = ran.nextInt(height);
                    int x2 = ran.nextInt(width);
                    int y2 = ran.nextInt(height);
                    g.drawLine(x1,y1,x2,y2);
                }
        //3.将图片发送响应
        ImageIO.write(image,"jpg",response.getOutputStream());
    }

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

这里使用了一个能产生随机颜色的内部类,里面有一个getcolor的方法来生成随机颜色

class color{
    
    
            public Color getcolor(){
    
    
                Random ra=new Random();
                int r = ra.nextInt(256);
                int g = ra.nextInt(256);
                int b = ra.nextInt(256);
                return new Color(r,g,b);
            }
        }

在将字符串绘制到图像上后要将字符串存储到session会话作用域中共享数据。

2.数据库操作的操作类

和上次的登录案例一样使用一样的方法使用druid数据库连接池和JDBCtemplate来操作数据库

1.封装数据库的数据的JavaBean对象

代码如下

package zsc.Servlet.JavaB;

public class Students {
    
    
    Integer id;
    String name;
    String password;

    public Integer getId() {
    
    
        return id;
    }

    public void setId(Integer id) {
    
    
        this.id = id;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public String getPassword() {
    
    
        return password;
    }

    public void setPassword(String password) {
    
    
        this.password = password;
    }

    @Override
    public String toString() {
    
    
        return "Students{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", possword='" + password + '\'' +
                '}';
    }
}

2.获取数据库连接池的工具类

代码如下

package zsc.Servlet.JDBC;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.naming.Context;
import javax.sql.DataSource;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

public class JDBCUtils {
    
    
    private static DataSource ds;
    static {
    
    
        //使用Druid数据连接池连接数据库

        try {
    
    
            Properties properties=new Properties();
            properties.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
            ds = DruidDataSourceFactory.createDataSource(properties);

        } catch (IOException e) {
    
    
            e.printStackTrace();
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }
    //获取连接池方法
    public static DataSource getdataSource(){
    
    
        return ds;
    }
    //获取连接方法
    public static Connection getconnection() throws SQLException {
    
    
        return ds.getConnection();
    }
    //关闭连接的方法
    public static void close(PreparedStatement ps, ResultSet rs,Connection con){
    
    
        if (ps!=null){
    
    
            try {
    
    
                ps.close();
            } catch (SQLException throwables) {
    
    
                throwables.printStackTrace();
            }
        }
        if (rs!=null){
    
    
            try {
    
    
                rs.close();
            } catch (SQLException throwables) {
    
    
                throwables.printStackTrace();
            }
        }
        if (con!=null){
    
    
            try {
    
    
                con.close();
            } catch (SQLException throwables) {
    
    
                throwables.printStackTrace();
            }
        }
    }
}

3.操作数据库的登录类

里面有一个登录的方法来查找该用户是否存在,如果不存在就返回-1,如果存在密码错误返回0,密码正确返回1
里面还有一个静态的Students的JavaBean对象来获取查询完后的Students对象
代码如下

package zsc.Servlet.DoMain;

import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import zsc.Servlet.JDBC.JDBCUtils;
import zsc.Servlet.JavaB.Students;

import java.util.Map;

public class Login {
    
    

    //1.实现JdbcTemplate对象,并且接收获取数据库连接池,该对象是私有的成员对象
    private JdbcTemplate jdbcTemplate=new JdbcTemplate(JDBCUtils.getdataSource());
    //创建一个Students对象,方便servlet获取查询后的Students对象
    public static Students stu=null;
    public int getLogin(Students student){
    
    
        try {
    
    
            //2.创建数据库查询语句
            // (查找该用户是否存在,如果不存在就返回-1,如果存在密码错误返回0,密码正确返回1)
            String sql="select * from studentTable1 where name=?";
            //3.使用queryForObject方法来操作查询语句
            stu = jdbcTemplate.queryForObject(sql,
                    new BeanPropertyRowMapper<Students>(Students.class),
                    student.getName());
            //4.如果报异常,那证明查找不到返回-1,对查找到的用户进行,密码判断
            if (stu.getPassword().equals(student.getPassword())){
    
    
                return 1;
                //用户名和密码都正确返回1
            }
            else {
    
    
                return 0;
                //密码错误返回0
            }
        } catch (DataAccessException e) {
    
    
            e.printStackTrace();
            return -1;
            //用户名错误或者没有该用户返回-1
        }
    }
}

3.使用工具类的servlet

该servlet使用工具类来操作数据库,接收返回值,和调用登录类里的Students(JavaBean)对象,然后进行登录情况的处理,请求转发和响应重定向

三次错误的处理是使用请求转发来跳转页面,都是跳转登录页面,而正确的处理使用响应重定向来跳转页面,跳转到success的jsp页面

package zsc.Servlet.Main;

import org.apache.commons.beanutils.BeanUtils;
import org.springframework.jdbc.core.JdbcTemplate;
import zsc.Servlet.DoMain.Login;
import zsc.Servlet.JavaB.Students;

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 javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;

@WebServlet("/LoginServle")
public class LoginServle extends HttpServlet {
    
    
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
        //解决中文乱码
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");

        //1.BeanUtils的populate静态方法来获取所有的请求参数,并且直接写进Students的javaBean对象中
        //创建javaBean对象,Students对象
        Students student=new Students();
        //将获取的所有请求参数封装到map集合中
        Map<String, String[]> parameterMap = request.getParameterMap();
        try {
    
    
            //使用populate方法
            BeanUtils.populate(student,parameterMap);
        } catch (IllegalAccessException e) {
    
    
            e.printStackTrace();
        } catch (InvocationTargetException e) {
    
    
            e.printStackTrace();
        }

        //2.判断验证码是否正确(如果正确进行登录的操作,如果不正确开始提示用户)
        //三次错误的处理是使用请求转发来跳转页面,而正确的处理使用响应重定向来跳转页面
        //获取页面输入的验证码
        String check = request.getParameter("check");
        //获取session对象,并且获取图像的验证码
        HttpSession session = request.getSession();
        String session_check = (String) session.getAttribute("check");
        //获取完session对象的的验证码,然后立马删除session里的验证码,使验证码为一次性的
        session.removeAttribute("check");
        if (session_check!=null&&session_check.equalsIgnoreCase(check)){
    
             //防止出现空指针异常,所以先判断一下是否为空忽略大小写的比较方法.equalsIgnoreCase
            //验证码一致时
            //获取数据库操作对象
            Login login=new Login();
            //使用.getLogin方法
            int loginInt = login.getLogin(student);
            //获取查询完数据库的students JavaBean对象
            Students stu = Login.stu;
            if (loginInt==-1){
    
    
                //请求转发
                request.setAttribute("student_wrong","没有该用户,或者用户名错误!");
                request.getRequestDispatcher("/index.jsp").forward(request,response);
            }
            else if (loginInt==0){
    
    
                //请求转发
                request.setAttribute("password_wrong","密码错误");
                request.getRequestDispatcher("/index.jsp").forward(request,response);
            }
            else {
    
    
                //响应重定向
                session.setAttribute("success_name",stu.getName());
                session.setAttribute("success_password",stu.getPassword());
                response.sendRedirect(request.getContextPath()+"/success.jsp");
            }
        }
        else {
    
    
            //验证码不一致时,使用请求转发,并且使用请求作用域存储错误信息
            //存储错误信息
            request.setAttribute("check_wrong","验证码错误");
            //转发到登录页面
            request.getRequestDispatcher("index.jsp").forward(request,response);
        }

        
    }

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

注意在获取完验证码的共享数据后一定要删除验证码的共享数据,然后在判断的时候要进行一次判空操作(防止出现空指针异常),这样就会使验证码是一次性的,在正确登录后点击浏览器上的返回,就不会出现验证码复用的问题

4.两个jsp页面

一个登录的主页面


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>登录</title>
    <style>
      *{
     
     
        margin: 0px;
        padding: 0px;
      }
      div{
     
     
        /*border: red solid 1px;*/
      }

      /*解决图片验证码单击的事件处理*/
    </style>
    <script type="text/javascript">
      window.onload=function () {
     
     
            document.getElementById("img1").onclick=function () {
     
     
              var date=new Date().getTime();
                this.src="/zsc/CheckDemo1?"+date;
            }
            document.getElementById("a1").onclick=function () {
     
     
                  var date=new Date().getTime();
                  var img=document.getElementById("img1");
                  img.src="/zsc/CheckDemo1?"+date;
            }
      }
    </script>
  </head>
  <body>
  <div style="background: aqua;width: 100%;height: 100%;position: absolute">
    <div style="position: absolute;left: 650px;top: 250px;">
      <form action="/zsc/LoginServle" method="post">
        用户名:<input type="text" name="name" placeholder="请输入用户名"><br><br>&nbsp;&nbsp;&nbsp;码:<input type="password" name="password" placeholder="请输入密码"><br><br>
        验证码:<input type="text" name="check" placeholder="请输入验证码"><br>
        <div style="position: absolute;left: 25px;top: 200px;">
          <input type="submit" value="登录" style="margin-left: 20px">
          <input type="reset" value="重置" style="margin-left: 100px">
        </div>

          <img src="/zsc/CheckDemo1" style="margin-top: 20px" id="img1">
          <a href="#" id="a1" style="text-decoration: none">看不清,换一张</a>
          <%--style="text-decoration: none"去超链接的下划线,超链接页面不刷新,设置href="#"--%>

          <div style="position: absolute;width: 250px;height: 20px;left: 250px;top: 10px;color: red">
            <%
              if (request.getAttribute("student_wrong")!=null){
                out.println(request.getAttribute("student_wrong"));

            }

              %>
          </div>
          <div style="position: absolute;width: 250px;height: 20px;left: 250px;top: 50px;color: red">
            <%
              if (request.getAttribute("password_wrong")!=null){
                out.println(request.getAttribute("password_wrong"));
              }

            %>
          </div>
          <div style="position: absolute;width: 250px;height: 20px;left: 250px;top: 90px;color: red">
            <%
              if (request.getAttribute("check_wrong")!=null){
                out.println(request.getAttribute("check_wrong"));
              }

            %>
          </div>
      </form>
    </div>
  </div>
  </form>
  </body>
</html>

一个登录成功重定向的页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登入成功</title>
</head>
<body>
<%
if (request.getSession().getAttribute("success_name")!=null){
    out.println(request.getSession().getAttribute("success_name"));
    out.println("<a href='/zsc/index.jsp'>注销登录</a>");
}
else {
    out.println("抱歉你未登录,请返回登录页面");
    out.println("<a href='/zsc/index.jsp'>登录</a>");
}
%>
</body>
</html>

里面使用java代码来对登录情况的提示语句进行处理

猜你喜欢

转载自blog.csdn.net/Jackbillzsc/article/details/108230645