前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >数据库实践第10次作业提要

数据库实践第10次作业提要

作者头像
凝神长老
发布2020-04-17 17:56:01
7740
发布2020-04-17 17:56:01
举报

数据库连接说明

代码语言:javascript
复制
public String DBDRIVER = "com.mysql.jdbc.Driver";
public String DBURL = "jdbc:mysql://www.jxtxzzw.com:3306/addresslist";
public String DBUSER = "jxtxzzw_dev";
public String DBPASS = "jxtxzzw_dev";

如果是 MySQL 8.0 及以上版本,需要修改驱动 com.mysql.jdbc.Drivercom.mysql.cj.jdbc.Driver 并安装对应驱动。

数据库用的是我的服务器上的数据库,数据库地址是 www.jxtxzzw.com:3306,数据库是 addresslist。 用户名和密码都是 jxtxzzw_dev,连接允许从任意主机发起(已开放安全组入方向、已允许任意主机连入),其余数据库账号和数据表已禁用远程访问。 如果需要配置本地数据库,可自行修改数据库地址、用户名和密码。

登录注销功能

如果只做一个假的登录功能,即点击登录按钮时跳转到登录页面,登录成功和失败分别跳转不同的页面,那么其实我直接在浏览器输入正确页面的 URL 也是可以访问的。

所以,需要状态管理。

登录、注销使用的是 session。

代码语言:javascript
复制
if (result) {
    // 使用request对象的getSession()获取session,如果session不存在则创建一个
    HttpSession session = request.getSession();
    // 将数据存储到session中
    session.setAttribute("username", adminname);
    response.sendRedirect("../AdminMain.jsp");
} else {
    response.sendRedirect("../LoginFail.jsp");
}

之后在所有授权页面只需要检查 session。

所有页面增加这个字段。

代码语言:javascript
复制
<%
String username = null;
session = request.getSession(false);
if (session != null)
    username = (String) session.getAttribute("username");
if (username != null) {
    out.println("用户登录成功,欢迎你:" + username);
%>
一些 HTML 代码,例如显示可操作的项目……  
<%
} else {
    out.println("请先登录");
}
%>

注销只需要手动设置 session 无效。

代码语言:javascript
复制
<body>
  <center>
    <%
      session = request.getSession();
      //手工调用session.invalidate方法,摧毁session
      session.invalidate();
    %>
    <h2>管理员注销成功!</h2>
    <table width="80%">
      <tr>
        <td><a href="AdminLogin.jsp">重新登录</a></td>
        <td><a href="index.jsp">回到主页</a></td>
      </tr>
    </table>
  </center>
</body>

查看校内所有教师信息

代码语言:javascript
复制
select * from teacher

因此直接查询,然后用 rs.next() 遍历所有的结果,依次打印。

直接 jsp 里面写代码运行就行了。

模糊搜索功能

代码语言:javascript
复制
select * from teacher where teacher_name like %?%

模糊查询就是用 like 功能,但是由于这必须要一次前后台通讯,必须点了提交以后把数据发到后台才行,所以表单的 action 是 servlet 的一个服务,然后在那里做好查询,把数据保存到一个 QueryResult 页面,并返回。

代码语言:javascript
复制
<form id="teacherquery" name="teacherquery" method="post"
      action="TeacherQueryResult.jsp">
代码语言:javascript
复制
String sql = "select * from teacher where teacher_name like '%" + teacher_name + "%'";
if (con != null) {
  rs = dm.executeQuery(sql);
}

添加、修改、删除教师信息

逻辑比较方便,就是获取所有用户输入的东西,然后往后台发送。

前端的展示就是罗列一堆文本框就好了。

代码语言:javascript
复制
……
<tr>
    <td align=right>所在系:</td>
    <td><select id="teacher_dept_id" name="teacher_dept_id"
                title="所在系">
        </select></td>
</tr>
<tr>
    <td align=right>职称:</td>
    <td><input name="teacher_title" type="text" title="职称" /></td>
</tr>
……

修改的时候只是文本框默认是有值的,默认值就从后台返回一个 Query,把指定教师原有的信息填充进去。

需要注意的是,教师 ID 应该被设置为只读。

修改和删除期望的操作位置应该是在罗列教师列表的页面,每一行增加一个操作按钮。

但是这个页面同时也是普通用户可以访问的,这意味着,要么会出现代码复制的现象,要么就要在这个页面中判断当前用户是不是管理员(是不是有合法的 session),然后进行分支选择,决定是否显示修改和删除按钮。

代码语言:javascript
复制
boolean adminLoggedIn = false;
String username = null;
session = request.getSession(false);
if (session != null)
    username = (String) session.getAttribute("username");
if (username != null)
    adminLoggedIn = true;
代码语言:javascript
复制
if (adminLoggedIn) {
    out.println("<td><a href=" + "TeacherModify.jsp?teacher_id=" + rs.getString("teacher_id")
                + ">修改</a>");
    out.println("<a href=" + "TeacherDelete.jsp?teacher_id=" + rs.getString("teacher_id")
                + ">删除</a></td>");
}

只有登录状态会增加这两列。

删除状态比较简单,传递 ID,然后直接执行删除。

同理,新增、修改、删除页面,必须判断是不是管理员。

代码语言:javascript
复制
session = request.getSession(false);
if (session != null)
    username = (String) session.getAttribute("username");
if (username != null) {
    out.println("用户登录成功,欢迎你:" + username);
    String sql = "delete from teacher where teacher_id='" + teacher_id + "'";
    if (con != null) {
        if (dm.executeUpdate(sql) > 0)
            out.println("删除成功");
        else
            out.println("删除失败");

    }
} else {
    out.println("请先登录");
}

同时,返回功能的实现也与用户有关,如果是未登录状态,则点击返回按钮会返回到主页,而登录状态下的返回按钮会返回到管理员的管理界面。

学院和学院编号

ID 是传递给后台的,前台应该展示学院的名字,因此做一个转换即可,前端显示的是名字,即 name 是名字,而 value 保留 ID。

但是如果只是显示系编号就非常简单。

如果需要显示系的名字而不是编号,也行,就是多做一次查询,根据系的 ID 去查名字。

但是要显示学院,就有点麻烦,需要嵌套比较多的查询次数。

当然也可以用自然连接,或者笛卡尔积等方法。

代码语言:javascript
复制
String sql = "select * from teacher join department on teacher_dept_id = dept_id";
代码语言:javascript
复制
out.println("<td>" + rs.getString("dept_name") + "</td>");

下一个问题是怎么查学院。

代码语言:javascript
复制
String sql = "select * from (teacher join department as d1 on teacher_dept_id = dept_id) join department as d2 on d1.father_id = d2.dept_id";
代码语言:javascript
复制
out.println("<th>学院</th>");
out.println("<th>系</th>");
out.println("<td>" + rs.getString("d2.dept_name") + "</td>");
out.println("<td>" + rs.getString("d1.dept_name") + "</td>");

注册 XML

如果遇到了 servlet,需要注册 XML。

管理员修改密码

与修改教师信息一样,首先判断是不是管理员登录,然后提供一个新的输入框,允许用户输入新密码,然后传递到后台。管理员用户名只读,不允许修改,并同时可以传递到后台方便处理。

简化了问题,没有做“重复密码”输入和校验。

学院和系的处理

father_id 是不是 0。

提供下拉框

下拉框比较简单。

代码语言:javascript
复制
<select id="dept_name" name="dept_name">
    <option value="100">这是 A 系</option>
    <option value="233">这是 B 系</option>
</select>

联动的下拉框

期望的结果应该是联动的下拉框。

必须先选学院,然后第二级的下拉框会根据学院的内容切换成那个学院下面的所有系。

然而,由于其他输入框内容没有填写,因此不能做后台交互,尽量全部前台完成。

当然,如果做后台 API 请求,那更好,但是为了简化问题(其实是懒得在这次作业上花太多时间),怎么方便怎么来,尽量前端处理。

前端处理的话,要用到 JavaScript。

逻辑比较方便,首先获取所有的系的信息,然后把所有的学院(father_id 为 0)添加到下拉框。

代码语言:javascript
复制
if (rs.getString("father_id").equals("0"))
    out.println("<option value = \"" + rs.getString("dept_id") + "\">"
                + rs.getString("dept_name") + "</option>");

然后传递信息只需要传递 value 还是方便的。

关键是第 2 级的下拉框内容。

可以有一个 onchange(),当第 1 级下拉框的内容改变的时候,自动触发这个函数。

于是,这个函数要做的事情就非常简单,就是把属于同一个学院的内容添加到下拉框。

由于后端不能获取前端的实时信息,而这里也不存在交互的可能(其实是懒得做),而前端可以获取后端的信息,所以信息流的方向就很明确了。

在之前,我开了一个 ArrayList,把所有的系的信息保留了下来,记录系编号、系名称、所属学院编号。

代码语言:javascript
复制
while (rs.next()) {
    ArrayList list = new ArrayList();
    list.add(rs.getString("dept_id"));
    list.add(rs.getString("dept_name"));
    list.add(rs.getString("father_id"));
    dept_list.add(list);
    if (rs.getString("father_id").equals("0"))
        out.println("<option value = \"" + rs.getString("dept_id") + "\">"
                    + rs.getString("dept_name") + "</option>");
}

于是,onchange() 函数需要同时处理前端和后端的代码。

遍历所有的系,如果所属学院的 ID 是一样的,添加到下拉框。

代码语言:javascript
复制
<script language="javascript">
    function fatherDeptOnChange() {
        var father_dept_id = document.getElementById("dept_father").value;
        var dept_select=document.getElementById("teacher_dept_id");
        dept_select.options.length=0; // 清空下拉框
        <%int len = 0;
        if (dept_list != null)
            len = dept_list.size();
        for (int i = 0; i < len; i++) {
            ArrayList list = (ArrayList) dept_list.get(i);
            String dept_id = (String) list.get(0);
            String dept_name = (String) list.get(1);
            String father_id = (String) list.get(2);%>
                if(father_dept_id==<%=father_id%>){
                   dept_select.options.add(new Option("<%=dept_name%>","<%=dept_id%>"));
        }
        <%}%>
    }
</script>

上面是添加部分的代码,修改部分也是类似的。

下拉框的默认值

修改部分的比较简单。

同样,在记录所有的 ArrayList 的时候,把符合条件的系添加到下拉框,并对其中完全匹配的条目设置为默认勾选。

代码语言:javascript
复制
if (rs2.getString("father_id").equals("0")) {
    out.println("<option value = \"" + rs2.getString("dept_id") + "\"");
    if (rs2.getString("dept_id").equals(father_id)) {
        out.println(" selected ");
    }
    out.println(">" + rs2.getString("dept_name") + "</option>");
}
代码语言:javascript
复制
<tr>
    <td align=right>所在系:</td>
    <td><select id="teacher_dept_id" name="teacher_dept_id"
                title="所在系">
        <%
           rs2.beforeFirst();
           while (rs2.next()) {
           if (rs2.getString("father_id").equals(father_id)) {
           out.println("<option value = \"" + rs2.getString("dept_id") + "\"");
           if (rs2.getString("dept_id").equals(rs.getString(3))) {
           out.println(" selected ");
           }
           out.println(">" + rs2.getString("dept_name") + "</option>");

           }
           }
           %>
            </select></td>
</tr>

对于添加教师的页面,由于一开始不会触发 onchange(),所以要有别的方法来触发,我这里选择了使用 bodyonload

代码语言:javascript
复制
<body onload="fatherDeptOnChange()">

其他需要交代的事情

  1. 注意前端、后端、数据库的编码要是 UTF-8,否则中文保存会出问题。 request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8");
  2. 注意变量的作用域。
  3. 注意非法操作时对象可能为 null,必须做特判。
  4. 注意 jsp 和 js 混合写的时候哪一部分是前端,哪一部分是后端,注意 <% %> 的嵌套关系。尤其是需要注意 if 条件,哪些是在后端做的,哪些是在前端做的,for 循环的嵌套、大括号的嵌套。
  5. 可选的触发是 onload,modi 不需要 onload,否则就算选中了对应的系,onload 之后也会被替换掉。
  6. 演示效果见:演示.mp4
  7. 详细代码请参考源代码部分
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-05-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 凝神长老和他的朋友们 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档