Java Web 登录系统示例:过滤器技术与 JDBC 数据库连接
在这篇博客中,我们将探讨一个简单的 Java Web 登录系统示例,重点介绍其中使用的过滤器技术以及 JDBC 数据库连接技术。这个示例包括后端代码和简单的前端代码,帮助你理解这些技术的实现和原理。
项目结构
过滤器技术
什么是过滤器?
过滤器(Filter)是 Java Web 开发中的一个强大工具,它可以在请求到达 Servlet 之前或响应返回客户端之前对请求和响应进行拦截和处理。过滤器可以用来执行诸如字符编码设置、跨域资源共享(CORS)、日志记录、权限检查等任务。
我们使用的过滤器
-
CharsetFilter: 设置请求和响应的字符编码,确保数据在传输过程中不会出现乱码问题。
-
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>
项目结构与组件作用
-
CharsetFilter:
-
作用: 确保请求和响应使用UTF-8编码,防止字符编码问题,特别是在处理非英文字符时。
-
实现: 在
doFilter
方法中设置请求和响应的字符编码为UTF-8。
-
-
CorsFilter:
-
作用: 处理跨域资源共享(CORS),允许来自不同域名的请求。
-
实现: 在
doFilter
方法中设置CORS相关的HTTP头,如Access-Control-Allow-Origin
等。
-
-
HttpResult:
-
作用: 作为数据传输对象(DTO),封装返回给客户端的数据,包含状态码、消息、结果数据和时间戳。
-
结构: 包含
code
、msg
、result
和time
字段。
-
-
DAO层(数据访问对象):
-
IStudentDao接口: 定义学生数据操作的方法,如保存、删除、更新和查询学生信息。
-
StudentDaoImpl类: 实现IStudentDao接口,使用JDBC连接MySQL数据库,执行CRUD操作。
-
-
Student实体类:
-
作用: 表示学生实体,包含学生ID、姓名、用户名、密码和成绩等属性。
-
结构: 使用Lombok注解简化getter和setter方法。
-
-
自定义异常类:
-
InvalidUserException: 用户名或密码错误时抛出。
-
UsernameEmptyException: 用户名为空时抛出。
-
UsernameErrorException: 用户名错误时抛出。
-
-
服务层:
-
IStudentService接口: 定义业务操作方法,如用户登录。
-
StudentServiceImpl类: 实现IStudentService接口,调用DAO层进行数据操作,并处理业务逻辑。
-
-
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>
流程概述
用户交互:
用户在登录页面输入用户名和密码,点击登录按钮。
请求处理:
前端通过AJAX将用户名和密码发送到
LoginServlet
。
LoginServlet
调用StudentServiceImpl
进行登录验证。业务逻辑:
服务层调用DAO层从数据库中查询用户信息。
验证用户名和密码,如果验证通过,返回成功响应;否则抛出异常。
响应返回:
LoginServlet
将结果封装在HttpResult
中,以JSON格式返回给前端。前端根据响应显示相应的消息。
总结
该项目展示了Java Web应用中过滤器、JDBC、服务层和前端交互的基本实现。通过各组件的协同工作,实现了简单的用户登录功能。在实际应用中,需进一步考虑安全性和性能优化。这个也存在很多问题,主要为了是理解一下web开发的业务逻辑思想,后期我们可以用spring框架来优化。
原文地址:https://blog.csdn.net/Broken_x/article/details/145228037
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!