自学内容网 自学内容网

Java Web 登录系统示例:过滤器技术与 JDBC 数据库连接

        在这篇博客中,我们将探讨一个简单的 Java Web 登录系统示例,重点介绍其中使用的过滤器技术以及 JDBC 数据库连接技术。这个示例包括后端代码和简单的前端代码,帮助你理解这些技术的实现和原理。

项目结构

过滤器技术

什么是过滤器?

        过滤器(Filter)是 Java Web 开发中的一个强大工具,它可以在请求到达 Servlet 之前或响应返回客户端之前对请求和响应进行拦截和处理。过滤器可以用来执行诸如字符编码设置、跨域资源共享(CORS)、日志记录、权限检查等任务。

我们使用的过滤器
  1. CharsetFilter: 设置请求和响应的字符编码,确保数据在传输过程中不会出现乱码问题。

  2. CorsFilter: 处理跨域请求,允许不同域的客户端访问我们的服务。

过滤器的实现

CharsetFilter.java

package com.ffyc.ee.filter;

import javax.servlet.*;
import java.io.IOException;

public class CharsetFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");
        chain.doFilter(request, response);
    }
}

 CorsFilter.java

package com.ffyc.ee.filter;

import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class CorsFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        httpResponse.setHeader("Access-Control-Allow-Origin", "*");
        httpResponse.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        httpResponse.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
        httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
        httpResponse.setHeader("Access-Control-Max-Age", "3600");

        chain.doFilter(request, response);
    }
}
过滤器的配置

在 web.xml 中配置过滤器:

<filter>
    <filter-name>CharsetFilter</filter-name>
    <filter-class>com.ffyc.ee.filter.CharsetFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>CharsetFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<filter>
    <filter-name>CorsFilter</filter-name>
    <filter-class>com.ffyc.ee.filter.CorsFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>CorsFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

JDBC 数据库连接

什么是 JDBC?

JDBC(Java Database Connectivity)是 Java 访问数据库的标准 API,允许 Java 程序连接并操作各种数据库。

我们使用的 JDBC 连接

在 StudentDaoImpl.java 中,我们使用 JDBC 连接到 MySQL 数据库,并执行 SQL 查询。

StudentDaoImpl.java

package com.ffyc.ee.dao.impl;

import com.ffyc.ee.dao.IStudentDao;
import com.ffyc.ee.entity.Student;

import java.sql.*;

public class StudentDaoImpl implements IStudentDao {

    private final String USERNAME = "root";
    private final String PASSWORD = "123456";
    private final String URL =
            "jdbc:mysql://localhost:3306/stu_db?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai";

    private Connection conn;
    private PreparedStatement pst;
    private ResultSet rs;

    public StudentDaoImpl() {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Student findByUsername(String username) {
        Student student = null;

        try {
            conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
            String sql = "SELECT * FROM stu_tab WHERE stu_username=?";
            pst = conn.prepareStatement(sql);
            pst.setString(1, username);

            rs = pst.executeQuery();

            if (rs.next()) {
                student = new Student();
                student.setId(rs.getInt("stu_id"));
                student.setName(rs.getString("stu_name"));
                student.setUsername(rs.getString("stu_username"));
                student.setPassword(rs.getString("stu_password"));
                student.setScore(rs.getDouble("stu_score"));
            }

        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                if (rs != null) rs.close();
                if (pst != null) pst.close();
                if (conn != null) conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return student;
    }
}

前端代码

登录页面
<!DOCTYPE html>
<html>
<head>
    <title>Login</title>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<h2>Login</h2>
<form id="loginForm">
    Username: <input type="text" id="username" name="username"/><br/>
    Password: <input type="password" id="password" name="password"/><br/>
    <button type="button" onclick="login()">Login</button>
</form>
<div id="message"></div>

<script>
    function login() {
        var username = $("#username").val();
        var password = $("#password").val();

        $.ajax({
            url: "login.do",
            type: "POST",
            data: {username: username, password: password},
            success: function(response) {
                $("#message").html("Status: " + response.code + ", Message: " + response.msg);
            },
            error: function(xhr, status, error) {
                $("#message").html("Error: " + error);
            }
        });
    }
</script>
</body>
</html>

项目结构与组件作用

  1. CharsetFilter:
    • 作用: 确保请求和响应使用UTF-8编码,防止字符编码问题,特别是在处理非英文字符时。

    • 实现: 在doFilter方法中设置请求和响应的字符编码为UTF-8。

  2. CorsFilter:
    • 作用: 处理跨域资源共享(CORS),允许来自不同域名的请求。

    • 实现: 在doFilter方法中设置CORS相关的HTTP头,如Access-Control-Allow-Origin等。

  3. HttpResult:
    • 作用: 作为数据传输对象(DTO),封装返回给客户端的数据,包含状态码、消息、结果数据和时间戳。

    • 结构: 包含codemsgresulttime字段。

  4. DAO层(数据访问对象):
    • IStudentDao接口: 定义学生数据操作的方法,如保存、删除、更新和查询学生信息。

    • StudentDaoImpl类: 实现IStudentDao接口,使用JDBC连接MySQL数据库,执行CRUD操作。

  5. Student实体类:
    • 作用: 表示学生实体,包含学生ID、姓名、用户名、密码和成绩等属性。

    • 结构: 使用Lombok注解简化getter和setter方法。

  6. 自定义异常类:
    • InvalidUserException: 用户名或密码错误时抛出。

    • UsernameEmptyException: 用户名为空时抛出。

    • UsernameErrorException: 用户名错误时抛出。

  7. 服务层:
    • IStudentService接口: 定义业务操作方法,如用户登录。

    • StudentServiceImpl类: 实现IStudentService接口,调用DAO层进行数据操作,并处理业务逻辑。

  8. LoginServlet:
    • 作用: 处理登录请求,调用服务层进行登录验证,并返回结果。

    • 实现: 使用HttpResult封装响应数据,处理异常情况,并返回JSON格式的响应。

前端页面
  • 登录页面:

    • 功能: 提供用户输入用户名和密码的表单,并通过AJAX提交登录请求。

    • 实现: 使用jQuery发送POST请求到login.do,并根据响应显示消息。

全部代码示例 

IStudentDao接口
package com.ffyc.ee.dao;

import com.ffyc.ee.entity.Student;

public interface IStudentDao {

    void save(Student student);

    void deleteById(int id);

    void update(Student student);

    Student findByUsername(String username);

    Student findByUsernameAndPassword(String username, String password);
}
IStudentDao( IStudentDao接口的实现类)
package com.ffyc.ee.dao.impl;

import com.ffyc.ee.dao.IStudentDao;
import com.ffyc.ee.entity.Student;

import java.sql.*;

/**
 * IStudentDao接口的实现类
 */
public class StudentDaoImpl implements IStudentDao {

    private final String USERNAME = "root";
    private final String PASSWORD = "123456";
    private final String URL =
            "jdbc:mysql://localhost:3306/stu_db?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai";

    private Connection conn;
    private PreparedStatement pst;
    private ResultSet rs;

    public StudentDaoImpl() {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void save(Student student) {

    }

    @Override
    public void deleteById(int id) {

    }

    @Override
    public void update(Student student) {

    }

    @Override
    public Student findByUsername(String username) {

        Student student = null;

        try {
            conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
            String sql = "SELECT * FROM  stu_tab WHERE stu_username=?";
            pst = conn.prepareStatement(sql);
            pst.setString(1, username);

            rs = pst.executeQuery();

            if (rs.next()) {
                student = new Student();
                student.setId(rs.getInt("stu_id"));
                student.setName(rs.getString("stu_name"));
                student.setUsername(rs.getString("stu_username"));
                student.setPassword(rs.getString("stu_password"));
                student.setScore(rs.getDouble("stu_score"));
            }

        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                if (rs != null) {
                    rs.close();
                }
                if (pst != null) {
                    pst.close();
                }
                if (conn != null) {
                    conn.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }

        }
        return student;
    }

    @Override
    public Student findByUsernameAndPassword(String username, String password) {
        return null;
    }
}
HttpResult
package com.ffyc.ee.dto;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;

/**
 * DTO类,给前端返回对象
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class HttpResult {

    private int code; //404, 500,200
    private String msg;  //后台信息
    private Object result;// 后台的结果
    private Date time; // 传输时间
}

 Student

package com.ffyc.ee.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 实体类,映射stu_tab表
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
    private Integer id;
    private String name;
    private String username;
    private String password;
    private Double score;
}
InvalidUserException
package com.ffyc.ee.exception;

/**
 * 无效的用户名或密码
 */
public class InvalidUserException extends RuntimeException {
    public InvalidUserException(String message) {
        super(message);
    }
}
UsernameEmptyException
package com.ffyc.ee.exception;

/**
 * 用户名为空异常
 */
public class UsernameEmptyException extends  RuntimeException{

    public UsernameEmptyException(String message) {
        super(message);
    }
}
UsernameErrorException
package com.ffyc.ee.exception;

/**
 * 用户名错误异常
 */
public class UsernameErrorException extends RuntimeException{

    public UsernameErrorException(String message) {
        super(message);
    }
}

 CharsetFilter

package com.ffyc.ee.filter;

import javax.servlet.*;
import java.io.IOException;

public class CharsetFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");
        chain.doFilter(request, response);
    }
}

CorsFilter 

package com.ffyc.ee.filter;

import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class CorsFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        // 设置跨域响应头
        httpResponse.setHeader("Access-Control-Allow-Origin", "*");
        httpResponse.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        httpResponse.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
        httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
        httpResponse.setHeader("Access-Control-Max-Age", "3600");

        // 继续处理请求
        chain.doFilter(request, response);
    }
}

 IStudentService接口

package com.ffyc.ee.service;

import com.ffyc.ee.entity.Student;

public interface IStudentService {

    Student login(String username, String password);
}

 StudentServiceImpl

package com.ffyc.ee.service.impl;

import com.ffyc.ee.dao.IStudentDao;
import com.ffyc.ee.dao.impl.StudentDaoImpl;
import com.ffyc.ee.entity.Student;
import com.ffyc.ee.exception.InvalidUserException;
import com.ffyc.ee.exception.UsernameEmptyException;
import com.ffyc.ee.exception.UsernameErrorException;
import com.ffyc.ee.service.IStudentService;

import java.util.Objects;

/**
 * IStudentService的实现类
 */
public class StudentServiceImpl implements IStudentService {

    private final IStudentDao studentDao;

    public StudentServiceImpl() {
        studentDao = new StudentDaoImpl();
    }

    @Override
    public Student login(String username, String password) {

        //1.验证用户名是否为空
        if (username == null || username.isEmpty())
            throw new UsernameEmptyException("用户名为空异常");

        Student student = studentDao.findByUsername(username);

        //student对象
        //2.返回null
        if (Objects.isNull(student)) throw new UsernameErrorException("用户名错误异常");

        //3.不为空,要验证密码
        if (!student.getPassword().equals(password)) throw new InvalidUserException("用户名|密码错误");

        return student;
    }
}
LoginServlet
package com.ffyc.ee.servlet;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.ffyc.ee.dto.HttpResult;
import com.ffyc.ee.entity.Student;
import com.ffyc.ee.exception.InvalidUserException;
import com.ffyc.ee.exception.UsernameEmptyException;
import com.ffyc.ee.exception.UsernameErrorException;
import com.ffyc.ee.service.IStudentService;
import com.ffyc.ee.service.impl.StudentServiceImpl;

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 java.io.IOException;
import java.util.Date;

@WebServlet(value = "/login.do")
public class LoginServlet extends HttpServlet {

    private IStudentService iss;


    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        iss = new StudentServiceImpl();
        HttpResult result=null;
        try {
            Student s = iss.login(username, password);
            result = new HttpResult(200, username + "登录成功", s, new Date());
        } catch (UsernameEmptyException e1) {
            result = new HttpResult(401, e1.getMessage(), null, new Date());
        } catch (UsernameErrorException e2) {
            result = new HttpResult(402, e2.getMessage(), null, new Date());
        } catch (InvalidUserException e3) {
            result = new HttpResult(403, e3.getMessage(), null, new Date());
        }

        ObjectMapper map = new ObjectMapper();
        String json = map.writeValueAsString(result);

        System.out.println(json);

        response.getWriter().println(json);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

 Web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <!--乱码-->



    <filter>
        <filter-name>CharsetFilter</filter-name>
        <filter-class>com.ffyc.ee.filter.CharsetFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>CharsetFilter</filter-name>
        <url-pattern>*.do</url-pattern>
    </filter-mapping>

    <!--跨域-->
    <filter>
        <filter-name>corsFilter</filter-name>
        <filter-class>com.ffyc.ee.filter.CorsFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>corsFilter</filter-name>
        <url-pattern>*.do</url-pattern>
    </filter-mapping>
</web-app>

流程概述 

  1. 用户交互:

    • 用户在登录页面输入用户名和密码,点击登录按钮。

  2. 请求处理:

    • 前端通过AJAX将用户名和密码发送到LoginServlet

    • LoginServlet调用StudentServiceImpl进行登录验证。

  3. 业务逻辑:

    • 服务层调用DAO层从数据库中查询用户信息。

    • 验证用户名和密码,如果验证通过,返回成功响应;否则抛出异常。

  4. 响应返回:

    • LoginServlet将结果封装在HttpResult中,以JSON格式返回给前端。

    • 前端根据响应显示相应的消息。        

总结

        该项目展示了Java Web应用中过滤器、JDBC、服务层和前端交互的基本实现。通过各组件的协同工作,实现了简单的用户登录功能。在实际应用中,需进一步考虑安全性和性能优化。这个也存在很多问题,主要为了是理解一下web开发的业务逻辑思想,后期我们可以用spring框架来优化。

 


原文地址:https://blog.csdn.net/Broken_x/article/details/145228037

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!