Gitee链接:https://gitee.com/fanggaolei/housekeeper-bookkeeping-system
本项目为个人练手项目,采用Servlet+JSP+BootStrap为主要技术点,适合JSP课程设计,练习Java开发,SQL查询
本项目为一个记账系统,实现用户进行注册登录后,进入主页面,对个人账单数据进行增啥改查,并提供丰富的查询聚合统计功能。
项目主要用到JSP做页面展示,使用Servlet,作为做后端数据的处理工作,使用MySql作为数据存储,项目采用标准的MVC架构实现即”模型-视图-控制器“三层架构实现(View—>Controler—>Service—>Dao),开发者可以通过个人需求对页面内容进行分层开发。
主要采用技术:
前端:bootstrap,javascript,JQuery,html,css
后端:Java,SQL,servlet
1.用户注册
用户注册提交表单后需要进行数据的校验功能,输入框不能为空,两次输入的密码必须一致,用户名和密码长度符合需求。
2.用户登录
用户输入个人正确的账号密码进入主页。输入数据必须不能为空,且必须符合长度规范才能提交。
3.用户主页
用户进入主页后,根据用户的个人ID,在账务数据库中查询,只属于个人的账户信息,并在页面左侧边栏显示账务的聚合信息,在中间部分主页显示具体的数据表单。
4.用户数据查询
显示所有数据,当用户进入主页后,直接根据用户ID查询当前用户的所有账务信息,并显示在页面,用户点击类型或时间查询,弹出对应的模态框,用户根据模态框的提示信息,填写对应格式的数据,如果数据格式不匹配,则表单无法进行提交。
5.用户删除数据
当用户点击对应信息的删除按钮,弹出模态框,提示用户是否确认删除当前信息,用户点击确认后,则将当前数据删除,并自动刷新当前页面
6.用户新增数据
当用户点击新增数据时,弹出对应新增数据表单,用户根据提示信息,将正确的内容输入,点击提交按钮即可提交数据,如果用户输入的数据不符合规范,页面弹出对应的提示,让用户填写符合格式的数据。
7.用户修改数据
当用户点击对应数据的修改按钮时,当前数据的信息回显到,修改数据模态框中,用户根据个人情况对数据进行修改,并且提交的数据必须是符合规范的,如果数据不符合格式要求,提示用户填写正确格式的数据。
8.用户退出登录
当用户退出登录后,用户不可通过返回页面继续修改页面数据,实现方式为,当用户点击 退出按钮,就销毁当前session,用户无法再修改数据。
MySql:5.7版本
Tomcat:7(使用Maven插件,在Pom.xml文件中配置即可使用,无需个人下载)
JDK:1.8版本
用户需要输入用户名
并需要输入两次相同密码才能注册成功
左边栏显示时间信息,以及当前用户数据信息
页面左边栏显示表格聚合信息
系统支持:用户数据的增删改查
将数据放入到对应的请求体中,通过页面的转发和重定向可以实现,两个servlrt的数据传输
request.setAttribute("list",zhangWu);
request.getAttribute("list",zhangWu);
1.servlet将数据放入到session中,jsp页面可以从session获取数据
2.Servlet将数据放到请求体重,并进行转发
request.setAttribute("data", "this is a data to send");
request.getRequestDispatcher("next.jsp").forward(request, response);
1.form表单
2.URL 发送get请求即可
3.session:jsp页面直接将数据存入到session中就可以了
下面是本项目的表单回显
主要说明:
1.获取到需要回显的值
2.将数据打包成一个对象
3.普通数据回显根据dom的name直接将数据写回
$("#money1").attr("value",strings1[2]);
4.下拉菜单回显
遍历下拉菜单的元素信息,当信息与当前相等的时候进行数据回显即可
let options = document.getElementById("xiaofei").options;for(let i = 0;i
这应该是最直接的写入方式
<%@ 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 %>
不能在标签内引入
org.apache.tomcat.maven tomcat7-maven-plugin 2.2 8080 / UTF-8
点击这个直接运行
使用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查找它
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;}
}
是 Apache 组织提供的一个开源 JDBC工具类库,它是对JDBC的简单封装,学习成本极低,并且使用dbutils能极大简化jdbc编码的工作量,同时也不会影响程序的性能。
commons-dbutilsAPI介绍:
工具类
一些说明:
查询结果的返回值:
ArrayHandler:把结果集中的第一行数据转成对象数组。ArrayListHandler:把结果集中的每一行数据都转成一个对象数组,再存放到List中。BeanHandler:将结果集中的第一行数据封装到一个对应的JavaBean实例中。BeanListHandler:将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里。//重点MapHandler:将结果集中的第一行数据封装到一个Map里,key是列名,value就是对应的值。//重点MapListHandler:将结果集中的每一行数据都封装到一个Map里,然后再存放到ListColumnListHandler:将结果集中某一列的数据存放到List中。KeyedHandler(name):将结果集中的每一行数据都封装到一个Map里(List
基本查询方法:
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 }
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客户
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既可以设置响应头,也可以完成响应体。
1.request
request范围较小一些,只是一个请求。
request对象的生命周期是针对一个客户端(说确切点就是一个浏览器应用程序)的一次请求,当请求完毕之后,request里边的内容也将被释放点 。
简单说就是你在页面上的一个操作,request.getParameter()就是从上一个页面中的url、form中获取参数。
但如果一个request涉及多个类,后面还要取参数,可以用request.setAttribute()和request.getAttribute()。
但是当结果输出之后,request就结束了。
2.session
session可以跨越很多页面。
而session的生命周期也是针对一个客户端,但是却是在别人设置的会话周期内(一般是20-30分钟),session里边的内容将一直存在,即便关闭了这个客户端浏览器 session也不一定会马上释放掉的。
可以理解是客户端同一个IE窗口发出的多个请求。
这之间都可以传递参数,比如很多网站的用户登录都用到了。
下一篇:Dockerfile自定义镜像