实验三 基于Ajax的联级下拉菜单实战

实验( 三 )

实验名称

编写基于Ajax的联级下拉菜单实战

实验目的 :

  1. 使用jQuery的Ajax发送json请求,实现三级联级下拉菜单(页面2)
  2. 后端使用servlet响应两个页面,通过页面1进入(可不实现登录注册功能,仅通过该页面进入)页面2,使用注解的过滤方式把其他请求重定向到页面1。
  3. 使用监听器显示在线人数
  4. 页面通过三级下拉菜单显示该班所有人员名单,数据库使用DBUtils连接

实验环境:

1、硬件要求:计算机一台

2、软件要求:Chrome浏览器、IE11浏览器、Firefox浏览器

页面1参考图

页面2参考图

只能通过页面1进入页面2,如果直接请求页面2的url,则使用servlet过滤器重定向到页面1。

菜单参考如上图片,通过不同条件查询该班所有人员名单,人员属性不少于两项(id,姓名),每个班级不少于两条数据,菜单不少于两项(至少2*2*2=8个班级表,每个表不少于两条数据)

实验步骤和内容:

1.数据库建立

建立一个名为test3的数据库,数据库中包含user和student两个表。

user表如图3-1所示。

图3-1  user表

student表如图3-2所示。

图3-2  student表

2.数据库连接

在druid.properties中进行数据库配置,确保数据库连接成功。数据库连接配置如图3-3所示。

图3-3  数据库连接配置

3.dao层编写

(1)BasicDAO编写

public class BasicDAO<T>: 这是一个泛型类,T 表示将要操作的对象的类型。通过泛型,可以使该 DAO 类适用于不同类型的对象。

private QueryRunner queryRunner = new QueryRunner();: 在这行代码中,创建了一个 QueryRunner 对象,它是 Apache Commons DbUtils 库中用于执行 SQL 查询和更新的类。

public int update(String sql, Object... parameters): 这个方法用于执行数据操作语言(DML)语句,例如 INSERT、UPDATE、DELETE 等。它接受一个 SQL 语句和可变参数 parameters,并返回受影响的行数。

public List<T> queryMulti(String sql, Class<T> clazz, Object... parameters): 这个方法用于执行查询语句,返回多行结果。它接受一个 SQL 语句、结果对象的类型 clazz 和可变参数 parameters,并返回一个包含查询结果的对象列表。

public T querySingle(String sql, Class<T> clazz, Object... parameters): 这个方法也用于执行查询语句,但是只返回一行结果。它接受一个 SQL 语句、结果对象的类型 clazz 和可变参数 parameters,并返回一个结果对象。

public Object queryScalar(String sql, Object... parameters): 这个方法用于执行查询语句,返回单个值。它接受一个 SQL 语句和可变参数 parameters,并返回一个单值结果。

核心代码如图3-4所示。

图3-4  BasicDAO核心代码

(2)StudentDAO层编写

编写一个用于查询学生信息的方法,它接受三个参数:专业(specialized)、年级(grade)和课程(lesson)。这个方法使用了一个SQL查询语句,通过传入的专业、年级和课程来筛选符合条件的学生信息。查询语句中的占位符(?)表示参数位置,用来防止SQL注入攻击。

接下来,使用了一个名为 queryMulti 的方法执行SQL查询,并将查询结果映射到 Student 类的对象列表中。这个方法可能是一个通用的查询方法,用来执行数据库查询并将结果映射到指定的实体类对象中。

核心代码如图3-5所示。

图3-5  StudentDAO核心代码

(3)UserDAO编写

public boolean queryUserByUsernameAndPassword(User user) {: 这是一个公有方法,返回布尔类型值,用于查询用户是否存在,方法接受一个User对象作为参数。

String sql = "select * from user where username = ? and password = ?";: 这里定义了一个 SQL 查询语句,用于在数据库中查询用户信息。这个查询语句使用了两个占位符?,分别用来表示用户名和密码。

User user1 = querySingle(sql, User.class, user.getUsername(), user.getPassword());: 这一行代码调用了一个叫做querySingle的方法来执行 SQL 查询,并将结果存储在一个User对象中。这个方法可能是一个数据库访问对象(DAO)中的一个方法,它的作用是执行查询并返回单个结果。

if (user1 != null) { return true; } else { return false; }: 这个条件语句检查了querySingle方法返回的结果。如果返回的user1对象不为null,意味着在数据库中找到了符合条件的用户,则返回true;否则返回false,表示未找到符合条件的用户。

核心代码如图3-6所示。

图3-6  UserDAO核心代码

4.bean层编写

(1)Student编写

类的属性包括:

id:表示学生的唯一标识符,类型为Integer。

studentId:表示学生的学号,类型为String。

name:表示学生的姓名,类型为String。

specialized:表示学生的专业,类型为String。

grade:表示学生的年级,类型为String。

lesson:表示学生所修课程,类型为String。

类包含了以下方法:

一个无参构造方法,用于创建一个空的Student对象。

一个包含所有属性的构造方法,用于创建具有指定属性值的Student对象。

get和set方法用于获取和设置类的属性值。

toString方法,用于返回一个包含所有属性值的字符串表示

核心代码如图3-7所示。

图3-7  Student核心代码

(2)User编写

package com.rjxy.javabean;:声明了该类所属的包名。

public class User {:定义了一个名为 User 的类。

private Integer id;、private String username;、private String password;:这三行声明了该类的私有属性,分别表示用户的ID、用户名和密码。

public User() { }:无参构造方法,用于创建一个空的 User 对象。

public User(Integer id, String username, String password) { }:带参数的构造方法,用于创建一个具有指定ID、用户名和密码的 User 对象。

public Integer getId() { }、public void setId(Integer id) { }、public String getUsername() { }、public void setUsername(String username) { }、public String getPassword() { }、public void setPassword(String password) { }:这些是公有的 getter 和 setter 方法,用于获取和设置 User 对象的属性值。

@Override:这是 Java 中的注解,表示下面的方法是对父类(Object 类)中的方法进行了重写。

public String toString() { }:重写了 toString() 方法,以便在将 User 对象转换为字符串时,能够得到包含对象属性值的可读性较好的字符串表示形式。

核心代码如图3-8所示。

图3-8  User核心代码

5.utlis层编写

JDBCUtilsByDruid编写

package com.rjxy.utils;: 这是声明了该类所在的包名。

import com.alibaba.druid.pool.DruidDataSourceFactory;: 导入了Druid连接池工厂类,用于创建Druid数据源。

import javax.sql.DataSource;: 导入了Java数据库连接池的DataSource接口,用于获取数据库连接。

import java.sql.Connection;, import java.sql.ResultSet;, import java.sql.SQLException;, import java.sql.Statement;: 导入了Java数据库连接相关的类,用于执行SQL语句和处理结果。

import java.util.Properties;: 导入了Java的Properties类,用于加载配置文件。

public class JDBCUtilsByDruid {: 声明了一个名为JDBCUtilsByDruid的公共类。

private static DataSource dataSource;: 声明了一个静态的DataSource对象dataSource,用于保存数据库连接池。

static { ... }: 这是一个静态初始化块,在类加载时执行。在这里,使用了DruidDataSourceFactory根据配置文件创建了数据库连接池。

Properties properties = new Properties(); ...: 创建了一个Properties对象,加载了名为druid.properties的配置文件,并通过DruidDataSourceFactory创建了数据源。

public static Connection getConnection() throws SQLException { ... }: 提供了一个静态方法getConnection()用于获取数据库连接,抛出了可能的SQL异常。

return dataSource.getConnection();: 在getConnection()方法中,返回了从数据源获取的数据库连接。

public static void close(ResultSet resultSet, Statement statement, Connection connection) { ... }: 提供了一个静态方法close()用于关闭数据库连接、语句和结果集。

if (resultSet != null) { resultSet.close(); } ...: 在close()方法中,检查传入的参数是否为null,如果不为null则关闭相应的资源。资源关闭后可能会抛出SQL异常,这里被捕获并抛出了RuntimeException。

核心代码如图3-9所示。

图3-9  JDBCUtilsByDruid核心代码

6.servlet层和监听器编写

(1)ManageFilter编写

@WebFilter("/views/manage/*"): 这是一个注解,指示该过滤器要拦截所有以"/views/manage/"开头的请求。换句话说,它会拦截所有访问"/views/manage/"目录下的资源的请求。

public class ManageFilter implements Filter {: 这是过滤器类的定义,实现了javax.servlet.Filter接口。它包含了过滤器的初始化、销毁和过滤方法。

public void init(FilterConfig config) throws ServletException { }: 这是过滤器的初始化方法。在此方法中,可以执行任何在过滤器初始化时需要完成的操作。在这个例子中,该方法为空,即没有初始化操作。

public void destroy() { }: 这是过滤器的销毁方法。在此方法中,可以执行任何在过滤器被销毁前需要完成的操作。

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException { }: 这是过滤器的核心方法,用于实际过滤请求。当一个请求被发送到与过滤器关联的 URL 时,容器将调用此方法。

核心代码如图3-10所示。

图3-10  ManageFilter核心代码

(2)OnlineCountListener编写

类声明和接口实现:

OnlineCountListener 类实现了 HttpSessionAttributeListener 接口,这个接口定义了用于监听 HttpSession 属性变化的方法。

attributeAdded 方法:

当向 HttpSession 中添加属性时,attributeAdded 方法被调用。

首先,它检查被添加的属性是否为 "username",这通常是用来标识用户登录状态的属性。

如果是 "username" 属性被添加,它会获取 ServletContext 对象,这个对象在整个Web应用程序中是唯一的,用来存储应用程序级别的数据。

然后,它打印出用户上线的消息,并更新在线用户数量(OnlineCount):

如果 OnlineCount 还不存在,说明这是第一个用户登录,将在线人数设置为1;

否则,将在线人数加1。

最后,将更新后的在线人数存储在 ServletContext 中。

attributeRemoved 方法:

当从 HttpSession 中移除属性时,attributeRemoved 方法被调用。

同样地,它检查被移除的属性是否为 "username"。

如果是 "username" 属性被移除,它会打印用户下线的消息,并更新在线用户数量:

如果在线人数为0,保持为0;

否则,将在线人数减1。

最后,更新后的在线人数存储在 ServletContext 中。

核心代码如图3-11所示。

图3-11  OnlineCountListener核心代码

(3)StudentServlet编写

定义了一个 StudentServlet 类,继承自 HttpServlet 类。

在类中创建了一个 StudentDAO 的实例,用于处理与学生相关的数据访问操作。

重写了 doGet 方法,该方法用于处理HTTP GET请求。在该方法中:

设置请求和响应的字符编码为UTF-8。

从请求参数中获取 specialized、grade 和 lesson 的值。

调用 StudentDAO 的方法查询符合条件的学生信息。

将查询结果转换为JSON格式的字符串。

将JSON字符串作为响应返回给客户端。

重写了 doPost 方法,该方法直接调用了 doGet 方法,实现了HTTP POST请求的处理。

核心代码如图3-12所示。

图3-12  StudentServlet核心代码

(4)UserServlet编写

doGet 方法:

接收 HTTP GET 请求,用于用户提交登录表单。

首先设置请求的字符编码为 UTF-8,以确保正确处理中文字符。

从请求参数中获取用户名和密码。

创建一个 User 对象,将获取到的用户名和密码封装到该对象中。

调用 UserDAO 类的 queryUserByUsernameAndPassword 方法,查询数据库中是否存在该用户。

如果存在该用户(queryUserByUsernameAndPassword 返回 true):

将用户名存储到会话(Session)中,以便在用户的整个会话期间保持登录状态。

将请求重定向(redirect)到菜单页面(/views/manage/menu.jsp)。

如果不存在该用户(queryUserByUsernameAndPassword 返回 false):

在请求属性中设置错误消息(errormsg),提示用户账号或密码错误。

将用户名存储到请求属性中,以便在重新加载登录页面时填充用户名字段。

将请求转发(forward)到登录页面(/views/login.jsp)。

doPost 方法:

重写了 doPost 方法,使其调用 doGet 方法,以便处理 POST 请求。这是为了在表单提交时统一处理逻辑,无论是 GET 还是 POST 请求。

核心代码如图3-13所示。

图3-13  UserServlet核心代码

(5)UserSignOutServlet编写

@Override

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    System.out.println("UserSignOutServlet被调用");

这是一个被覆盖的 doGet 方法,用于处理 HTTP GET 请求。它首先打印一条日志,表明该 Servlet 被调用了。

    request.getSession().removeAttribute("username");

这一行代码从当前会话中移除了名为 "username" 的属性。通常情况下,"username" 是在用户登录时存储在会话中的,所以移除它相当于让用户从会话中注销。

    request.getRequestDispatcher("/views/signout.html").forward(request,response);

这一行代码将请求转发到 "/views/signout.html" 页面,该页面通常用于展示用户已经成功注销的消息或者其他相关信息。

接下来的 doPost 方法调用了 doGet 方法,这是为了确保无论是 POST 请求还是 GET 请求,都能执行相同的注销逻辑。

核心代码如图3-14所示。

图3-14  UserSignOutServlet核心代码

7.jsp页面编写

(1)login.jsp编写

<title>登录页面</title>:设置页面的标题为"登录页面"。

<base href="<%=request.getContextPath() + "/"%>">:这是一个基准标签,用于设置页面中相对链接的基础路径。<%=request.getContextPath() %>用于获取当前web应用的上下文路径,然后在末尾添加斜杠,以确保相对路径的正确性。

.input1{width: 200px;}:定义了一个类名为input1的样式,设置其宽度为200像素。

<form action="userServlet" method="post">:一个表单元素,用于提交用户登录信息到名为"userServlet"的Servlet,并使用POST方法提交。

<h1>登录</h1>:页面标题,显示为"登录"。

用户名: <input type="text" class="input1" name="username" value="${requestScope.username}">:输入用户名的文本框,使用了类名为input1的样式,name属性设置为"username",并设置默认值为${requestScope.username},${}是EL(Expression Language)表达式,用于在JSP中动态地获取和展示数据。

密码: <input type="password" class="input1" name="password">:输入密码的文本框,类似地,但输入类型为密码,用户输入的字符会被隐藏。

<input type="submit" value="登录">:提交按钮,用户点击后将提交表单数据。

<span>${requestScope.errormsg}</span>:用于显示错误消息的span标签,内容为${requestScope.errormsg},即在Servlet中设置的错误消息。

核心代码如图3-15所示。

图3-15  login.jsp核心代码

(2)menu.jsp编写

基本结构:

contentType="text/html;charset=UTF-8":指定页面内容类型和字符编码。

<base href="<%=request.getContextPath() + "/"%>">:设置页面中相对路径的基础路径为当前请求的上下文路径。

样式和脚本引入:

引入了jQuery库:<script type="text/javascript" src="script/jquery-3.6.0.min.js"></script>。

定义了一些样式,其中 .option1 类被用于调整下拉菜单的宽度。

JavaScript部分:

使用jQuery库,确保在文档加载完成后执行代码。

给按钮 #btn1 绑定了点击事件处理函数,当按钮被点击时,发送AJAX请求到 studentServlet。

AJAX请求中包括了三个下拉菜单中当前选择的值:specialized, grade, lesson。

请求成功时,通过循环遍历返回的数据,在表格中动态生成学生信息。

HTML部分:

一个显示当前在线人数的 <div> 元素,使用了EL表达式 ${applicationScope.OnlineCount} 来获取应用程序范围内的在线人数。

一个表单,其中包含三个下拉菜单和两个按钮:

下拉菜单 #specialized, #grade, #lesson 分别用于选择专业、年级和班级。

一个按钮 #btn1 用于触发AJAX请求,执行查询操作。

另一个按钮 #btn2 用于提交退出登录的表单。

一个表格用于显示学生信息,其中包含表头和一个空的 <tbody> 元素,该元素将在AJAX请求成功后动态填充学生信息。

核心代码如图3-16所示。

图3-16  menu.jsp核心代码

8.效果实现

(1)启动tomcat服务器,进入页面一。如图3-17所示。

图3-17 主页面

(2)当输入错误的用户名或者密码时,提示错误信息。如图3-18所示。

图3-18 登录错误提示

(3)当输入正确的用户名和密码后,进行页面跳转。如图3-19所示。

图3-19 跳转页面

(4)在下拉框筛选信息后,点击查询,即可获得相应查询结果。如图3-20所示。

图3-20 查询结果

(5)点击退出登录按钮,即可跳转到退出页面。如图3-21所示。

图3-21 退出页面

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值