# 管家婆记账系统 **Repository Path**: vergil_code/housekeeper-bookkeeping-system ## Basic Information - **Project Name**: 管家婆记账系统 - **Description**: 😃本项目为管家婆记账系统,主要对个人用户的数据进行增删改查操作,其中查询功能提供了,聚合查询,分组查询,时间查询等功能,项目主要采用JSP+Servlet技术,前端采用Bootstrap和JS。适合课程设计,练习前端、SQL、Java编程。 - **Primary Language**: Unknown - **License**: MulanPSL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 3 - **Created**: 2024-11-13 - **Last Updated**: 2024-11-13 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ### 项目概述   **本项目为一个记账系统,实现用户进行注册登录后,进入主页面,对个人账单数据进行增啥改查,并提供丰富的查询聚合统计功能。** ​ **项目主要用到JSP做页面展示,使用Servlet,作为做后端数据的处理工作,使用MySql作为数据存储,项目采用标准的MVC架构实现即”模型-视图-控制器“三层架构实现(View--->Controler--->Service--->Dao),开发者可以通过个人需求对页面内容进行分层开发。**   **主要采用技术:**   **前端:bootstrap,javascript,JQuery,html,css**   **后端:Java,SQL,servlet** ### 1.需求说明 **1.用户注册**   用户注册提交表单后需要进行数据的校验功能,输入框不能为空,两次输入的密码必须一致,用户名和密码长度符合需求。 **2.用户登录**   用户输入个人正确的账号密码进入主页。输入数据必须不能为空,且必须符合长度规范才能提交。 **3.用户主页**   用户进入主页后,根据用户的个人ID,在账务数据库中查询,只属于个人的账户信息,并在页面左侧边栏显示账务的聚合信息,在中间部分主页显示具体的数据表单。 **4.用户数据查询**   显示所有数据,当用户进入主页后,直接根据用户ID查询当前用户的所有账务信息,并显示在页面,用户点击类型或时间查询,弹出对应的模态框,用户根据模态框的提示信息,填写对应格式的数据,如果数据格式不匹配,则表单无法进行提交。 **5.用户删除数据**   当用户点击对应信息的删除按钮,弹出模态框,提示用户是否确认删除当前信息,用户点击确认后,则将当前数据删除,并自动刷新当前页面 **6.用户新增数据**   当用户点击新增数据时,弹出对应新增数据表单,用户根据提示信息,将正确的内容输入,点击提交按钮即可提交数据,如果用户输入的数据不符合规范,页面弹出对应的提示,让用户填写符合格式的数据。 **7.用户修改数据**   当用户点击对应数据的修改按钮时,当前数据的信息回显到,修改数据模态框中,用户根据个人情况对数据进行修改,并且提交的数据必须是符合规范的,如果数据不符合格式要求,提示用户填写正确格式的数据。 **8.用户退出登录**   当用户退出登录后,用户不可通过返回页面继续修改页面数据,实现方式为,当用户点击 退出按钮,就销毁当前session,用户无法再修改数据。 ### 3.项目展示 #### 1.登录页面 ![image-20230319155848386](https://pic-1313413291.cos.ap-nanjing.myqcloud.com/image-20230414231510732.png) #### 2.注册页面 ![image-20230414231527743](https://pic-1313413291.cos.ap-nanjing.myqcloud.com/image-20230414231527743.png) #### 3.主页面 ![image-20230319155935318](https://pic-1313413291.cos.ap-nanjing.myqcloud.com/image-20230319155935318.png) #### 4.增删改查模态框 ![image-20230319155957094](https://pic-1313413291.cos.ap-nanjing.myqcloud.com/image-20230319155957094.png) ![image-20230319160027208](https://pic-1313413291.cos.ap-nanjing.myqcloud.com/image-20230319160027208.png) ![image-20230319160048627](https://pic-1313413291.cos.ap-nanjing.myqcloud.com/image-20230319160048627.png) ![image-20230319160107824](https://pic-1313413291.cos.ap-nanjing.myqcloud.com/image-20230319160107824.png) ![image-20230319160128063](https://pic-1313413291.cos.ap-nanjing.myqcloud.com/image-20230319160128063.png) ### 4.运行环境说明 MySql:5.7版本 Tomcat:7(使用Maven插件,在Pom.xml文件中配置即可使用,无需个人下载) JDK:1.8版本 ### 5.开发问题 #### **1.servlet如何向另外一个servlet传值?** 将数据放入到对应的请求体中,通过页面的转发和重定向可以实现,两个servlrt的数据传输 ``` request.setAttribute("list",zhangWu); request.getAttribute("list",zhangWu); ``` #### **2.servlet如何向JSP页面传值?** 1.servlet将数据放入到session中,jsp页面可以从session获取数据 2.Servlet将数据放到请求体重,并进行转发 ```java request.setAttribute("data", "this is a data to send"); request.getRequestDispatcher("next.jsp").forward(request, response); ``` #### **3.JSP如何向Servlet传值?** 1.form表单 2.URL 发送get请求即可 3.session:jsp页面直接将数据存入到session中就可以了 #### **4.JS如何将数据回显到修改模态框中** 下面是本项目的表单回显 主要说明: 1.获取到需要回显的值 2.将数据打包成一个对象 3.普通数据回显根据dom的name直接将数据写回 ``` $("#money1").attr("value",strings1[2]); ``` 4.下拉菜单回显 遍历下拉菜单的元素信息,当信息与当前相等的时候进行数据回显即可 ``` let options = document.getElementById("xiaofei").options; for(let i = 0;i var Zhanghu=new Object(); function upimg(id){ var res=id; //将当前ID数据传递给删除模态框提交到servlet中 var box = document.getElementById("s") box.innerText=res //box1.innerText=res //将id值传给input标签 $("#imgtalk").attr("value",res); $("#imgtalk1").attr("value",res); var attribute = document.getElementById(id).getAttribute("value"); console.log(attribute) var strings1 = attribute.split("="); console.log(strings1[0]); Zhanghu.zwid=strings1[0]; Zhanghu.flname=strings1[1]; Zhanghu.money=strings1[2]; Zhanghu.zhanghu=strings1[3]; Zhanghu.createtime=strings1[4]; Zhanghu.description=strings1[5]; Zhanghu.userid=strings1[6]; huixian(strings1); } function huixian(strings1){ console.log(strings1[0]); console.log(strings1[1]); $("#money1").attr("value",strings1[2]); $("#type1").attr("value",strings1[3]); $("#time1").attr("value",strings1[4]); $("#desc").attr("value",strings1[5]); let options = document.getElementById("xiaofei").options; for(let i = 0;i ``` #### 5.如何向JSP页面直接写数据 这应该是最直接的写入方式 ``` <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> Insert title here <% request.setCharacterEncoding("utf-8");//解决中文乱码的问题 String name = request.getParameter("uname"); String password = request.getParameter("pwd"); String sex = request.getParameter("sex"); String []favour = request.getParameterValues("duo"); String email = request.getParameter("email"); %>

账号:<%=name %>

密码:<%=password %>

性别:<%=sex %>

爱好: <% /* for(String c : favour){ out.println(c + " "); } */ for(int i = 0 ; i < favour.length ; i++){ String message = favour[i]; out.print(message+" "); } %>

邮箱:<%=email %>

``` #### 6.maven中tomcat7插件配置的问题? 不能在标签内引入 ``` org.apache.tomcat.maven tomcat7-maven-plugin 2.2 8080 / UTF-8 ``` 点击这个直接运行 ![image-20230319165526792](https://pic-1313413291.cos.ap-nanjing.myqcloud.com/image-20230319165526792.png) 使用servlet必须将组件配置为 ``` provided ``` scope:这个项目在编译,测试,运行阶段都需要这个jar包在classpath中 provided:可以认为这个provided是目标容器已经provide这个jar。换句话说,它只影响到编译,测试阶段。而在运行阶段,假定目标的容器(比如我们这里的tomcat容器)已经提供了这个jar包,app可以直接使用容器提供的jar,所以无需我们打包对应的jar包了。 import:解决maven继承(单)问题,Maven的继承和Java的继承一样,是无法实现多重继承的,一个子模块只能有一个标签。如果这个父模块有十几个子模块,那这个父模块的dependencyManagement会包含大量的依赖,不利于管理。 runtime:表示dependency不作用在编译时,但会作用在运行和测试时,如JDBC驱动,适用运行和测试阶段。 test:表示dependency作用在测试时,不作用在运行时。 只在测试时使用,用于编译和运行测试代码。不会随项目发布。 system:跟provided 相似,但是在系统中要以外部JAR包的形式提供,maven不会在repository查找它 ![image-20230319165620434](https://pic-1313413291.cos.ap-nanjing.myqcloud.com/image-20230319165620434.png) #### 7.JS如何实现简单form表单的数据校验? ```
``` #### 8.commons-dbcp连接池的基本配置? commons-dbcp.jar,commons-pool.jar由于建立数据库连接是一个非常耗时耗资源的行为,所以通过连接池预先同数据库建立一些连接,放在内存中,应用程序需要建立数据库连接时直接到连接池中申请一个就行,用完后再放回去。 ``` package com.fang.gjp.util; /* * 获取数据库连接的工具类 * 实现连接池,dbcp连接池 */ import javax.sql.DataSource; import org.apache.commons.dbcp.BasicDataSource; public class JDBCUtils{ //创建BasicDataSource对象 private static BasicDataSource datasource = new BasicDataSource(); //静态代码块,实现必要参数设置 static{ datasource.setDriverClassName("com.mysql.jdbc.Driver"); datasource.setUrl("jdbc:mysql://127.0.0.1:3306/gjp?useUnicode=true&serverTimezone=GMT&characterEncoding=UTF-8&useSSL=false"); datasource.setUsername("root"); datasource.setPassword("fgl123"); datasource.setMaxActive(10); datasource.setMaxIdle(5); datasource.setMinIdle(2); datasource.setInitialSize(10); } public static DataSource getDataSource(){ return datasource; } } ``` #### 9.commons-dbutils的说明? 是 Apache 组织提供的一个开源 JDBC工具类库,它是对JDBC的简单封装,学习成本极低,并且使用dbutils能极大简化jdbc编码的工作量,同时也不会影响程序的性能。 **commons-dbutilsAPI介绍:** - org.apache.commons.dbutils.QueryRunner - org.apache.commons.dbutils.ResultSetHandler   工具类 - org.apache.commons.dbutils.DbUtils 一些说明: **查询结果的返回值:** ``` ArrayHandler:把结果集中的第一行数据转成对象数组。 ArrayListHandler:把结果集中的每一行数据都转成一个对象数组,再存放到List中。 BeanHandler:将结果集中的第一行数据封装到一个对应的JavaBean实例中。 BeanListHandler:将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里。//重点 MapHandler:将结果集中的第一行数据封装到一个Map里,key是列名,value就是对应的值。//重点 MapListHandler:将结果集中的每一行数据都封装到一个Map里,然后再存放到List ColumnListHandler:将结果集中某一列的数据存放到List中。 KeyedHandler(name):将结果集中的每一行数据都封装到一个Map里(List),再把这些map再存到一个map里,其key为指定的列。 ScalarHandler:将结果集第一行的某一列放到某个对象中。//重点 ``` **基本查询方法:** ``` public static void delete()throws SQLException{ 33 //创建QueryRunner类对象 34 QueryRunner qr = new QueryRunner(); 35 //写删除的SQL语句 36 String sql = "DELETE FROM classmate WHERE id<=?"; 37 //调用QueryRunner方法update 38 int row = qr.update(conn, sql, 10); 39 System.out.printf("已经有[%d]发生了改变",row); 40 /* 41 * 判断insert,update,delete执行是否成功 42 * 对返回值row判断 43 * if(row>0) 执行成功 44 */ 45 DbUtils.closeQuietly(conn); 46 } 47 48 /* 49 * 定义方法,使用QueryRunner类的方法update将数据表的数据修改 50 */ 51 public static void update()throws SQLException{ 52 //创建QueryRunner类对象 53 QueryRunner qr = new QueryRunner(); 54 //写修改数据的SQL语句 55 String sql = "UPDATE classmate SET age=? WHERE name=?"; 56 //定义Object数组,存储?中的参数,注意传入的位置哟,不要把顺序写反了! 57 Object[] params = {18,"尹正杰"}; 58 //调用QueryRunner方法update 59 int row = qr.update(conn, sql, params); 60 System.out.printf("已经有[%d]发生了改变",row); 61 DbUtils.closeQuietly(conn); 62 } 63 64 /* 65 * 定义方法,使用QueryRunner类的方法update向数据表中,添加数据 66 */ 67 public static void insert()throws SQLException{ 68 //创建QueryRunner类对象 69 QueryRunner qr = new QueryRunner(); 70 String sql = "INSERT INTO classmate VALUES(?,?,?,?,?,?,?,?,?,?)"; 71 //将三个?占位符的实际参数,写在数组中 72 Object[] params = {null,"方合意",24,"python开发工程师",100,60,89,94,92,87}; 73 //调用QueryRunner类的方法update执行SQL语句 74 System.out.println(conn); 75 int row = qr.update(conn, sql, params); 76 System.out.printf("已经有[%d]发生了改变",row); 77 DbUtils.closeQuietly(conn); 78 } ``` #### 10.HttpServlet的请求响应流程 HttpServlet的请求响应流程 Web客户向Servlet容器发出Http请求 Servlet容器解析Web客户的Http请求 Servlet容器创建一个HttpRequest对象,在这个对象中封装Http请求信息 Servlet容器创建一个HttpResponse对象 Servlet容器调用HttpServlet的service方法,把HttpRequest和HttpResponse对象作为service方法的参数传给HttpServlet对象 HttpServlet调用HttpRequest的有关方法,获取HTTP请求信息 HttpServlet调用HttpResponse的有关方法,生成响应数据 Servlet容器把HttpServlet的响应结果传给Web客户 #### 11.请求转发和请求重定向的区别? getRequestDispatcher()包含两个重要方法,分别是请求转发和请求包含。一个请求跨多个Servlet时,需要使用请求转发和请求包含。 首先需要获得一个RequestDispatcher 对象:RequestDispatcher rd = request.getRequestDispatcher("/MyServlet"); 请求转发: rd.forward( request , response ); 留头不留体 请求包含: rd.include( request , response); 都留 需注意的是,无论是请求转发还是请求包含,都在一个请求范围内!使用同一个request和response! 请求转发和请求包含的区别 请求转发:由下一个Servlet完成响应体,当前Servlet可以设置响应头(留头不留体)。举个例子,AServlet请求转发到BServlet,那么AServlet不能够使用response.getWriter() 和response.getOutputStream()向客户端输出响应体,但可以使用response.setContentType("text/html;charset=utf-8") 设置响应头。而在BServlet中可以输出响应体。 请求包含:由两个Servlet共同完成响应体(留头又留体)。同样用上面的例子,AServlet请求包含到BServlet,那么AServlet既可以设置响应头,也可以完成响应体。 #### 12.request和session的区别 **1.request** request范围较小一些,只是一个请求。 request对象的生命周期是针对一个客户端(说确切点就是一个浏览器应用程序)的一次请求,当请求完毕之后,request里边的内容也将被释放点 。 简单说就是你在页面上的一个操作,request.getParameter()就是从上一个页面中的url、form中获取参数。 但如果一个request涉及多个类,后面还要取参数,可以用request.setAttribute()和request.getAttribute()。 但是当结果输出之后,request就结束了。 **2.session** session可以跨越很多页面。 而session的生命周期也是针对一个客户端,但是却是在别人设置的会话周期内(一般是20-30分钟),session里边的内容将一直存在,即便关闭了这个客户端浏览器 session也不一定会马上释放掉的。 可以理解是客户端同一个IE窗口发出的多个请求。 这之间都可以传递参数,比如很多网站的用户登录都用到了。