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.需求说明
1.用户注册
用户注册提交表单后需要进行数据的校验功能,输入框不能为空,两次输入的密码必须一致,用户名和密码长度符合需求。
2.用户登录
用户输入个人正确的账号密码进入主页。输入数据必须不能为空,且必须符合长度规范才能提交。
3.用户主页
用户进入主页后,根据用户的个人ID,在账务数据库中查询,只属于个人的账户信息,并在页面左侧边栏显示账务的聚合信息,在中间部分主页显示具体的数据表单。
4.用户数据查询
显示所有数据,当用户进入主页后,直接根据用户ID查询当前用户的所有账务信息,并显示在页面,用户点击类型或时间查询,弹出对应的模态框,用户根据模态框的提示信息,填写对应格式的数据,如果数据格式不匹配,则表单无法进行提交。
5.用户删除数据
当用户点击对应信息的删除按钮,弹出模态框,提示用户是否确认删除当前信息,用户点击确认后,则将当前数据删除,并自动刷新当前页面
6.用户新增数据
当用户点击新增数据时,弹出对应新增数据表单,用户根据提示信息,将正确的内容输入,点击提交按钮即可提交数据,如果用户输入的数据不符合规范,页面弹出对应的提示,让用户填写符合格式的数据。
7.用户修改数据
当用户点击对应数据的修改按钮时,当前数据的信息回显到,修改数据模态框中,用户根据个人情况对数据进行修改,并且提交的数据必须是符合规范的,如果数据不符合格式要求,提示用户填写正确格式的数据。
8.用户退出登录
当用户退出登录后,用户不可通过返回页面继续修改页面数据,实现方式为,当用户点击 退出按钮,就销毁当前session,用户无法再修改数据。
2.运行环境说明
MySql:5.7版本
Tomcat:7(使用Maven插件,在Pom.xml文件中配置即可使用,无需个人下载)
JDK:1.8版本
3.页面展示
1.登录页面
2.注册页面
用户需要输入用户名
并需要输入两次相同密码才能注册成功
3.主页面
左边栏显示时间信息,以及当前用户数据信息
4.增删改查模态框
页面左边栏显示表格聚合信息
系统支持:用户数据的增删改查
4.开发问题
1.servlet如何向另外一个servlet传值?
将数据放入到对应的请求体中,通过页面的转发和重定向可以实现,两个servlrt的数据传输
request.setAttribute("list",zhangWu);
request.getAttribute("list",zhangWu);
2.servlet如何向JSP页面传值?
1.servlet将数据放入到session中,jsp页面可以从session获取数据
2.Servlet将数据放到请求体重,并进行转发
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<options.length;i++){
if(options[i].value==strings1[1]){//根据id选中阿里
options[i].selected = true;
}
}
<script type="text/javascript">
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<options.length;i++){
if(options[i].value==strings1[1]){//根据id选中阿里
options[i].selected = true;
}
}
let options1 = document.getElementById("type1").options;
for(let i = 0;i<options.length;i++){
if(options1[i].value==strings1[3]){//根据id选中阿里
options1[i].selected = true;
}
}
}
</script>
5.如何向JSP页面直接写数据
这应该是最直接的写入方式
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
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");
%>
<p>账号:<%=name %></p>
<p>密码:<%=password %></p>
<p>性别:<%=sex %></p>
爱好:
<%
/* for(String c : favour){
out.println(c + " ");
}
*/
for(int i = 0 ; i < favour.length ; i++){
String message = favour[i];
out.print(message+" ");
}
%>
<p>邮箱:<%=email %></p>
</body>
</html>
6.maven中tomcat7插件配置的问题?
不能在标签内引入
<plugins>
<!-- 配置Tomcat插件 -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>8080</port>
<path>/</path>
<uriEncoding>UTF-8</uriEncoding>
</configuration>
</plugin>
</plugins>
点击这个直接运行
使用servlet必须将组件配置为
<scope>provided</scope>
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查找它
7.JS如何实现简单form表单的数据校验?
<form action="/register" method="post" id="registform" name="form1" onSubmit="return beforeSubmiti(this);">
<input type="text" name="name" placeholder="name" class="input-item">
<input type="password" name="password" placeholder="password" class="input-item">
<input type="password" name="password2" placeholder="password notarize" class="input-item">
<button class="btnn" type="submit">Sign Up</button>
</form>
<script type="text/javascript">
function beforeSubmiti(form1){
if(form1.name.value==''){
alert('用户名不能为空!');
form1.name.focus();
return false;
}
if(form1.password.value==''){
alert('密码不能为空!');
form1.password.focus();
return false;
}
if(form1.password.value.length<6){
alert('密码至少为6位,请重新输入!');
form1.password.focus();
return false;
}
if(form1.password.value!=form1.password2.value) {
alert('你两次输入的密码不一致,请重新输入!');
form1.password2.focus();
return false;
}
return true;
}
</script>
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再存到一个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窗口发出的多个请求。
这之间都可以传递参数,比如很多网站的用户登录都用到了。