一、系统概述
系统名称:找本书网上商城
源码下载:https://github.com/LiuJian0806/shopping
系统说明:本系统主要分为两个模块,用户模块及管理员模块。用户模块中,用户能够对商城的商品进行浏览、搜索,并可查看商品的详细信息,加入购物车、收藏商品、购买商品,查看购物车等功能;管理员模块中可以实现添加商品,管理用户订单等功能。
二、程序组成及代码说明
1、 系统设计
系统采用MVC框架开发,实现前端视图及后端数据处理实现分离,提高系统代码的刻度性。在前端开发中,主要采用HTML+CSS+JS进行前端页面开发,并通过AJAX技术实现前后端数据交互,并在视图中做出相应的动作。后端采用servlet技术,对前端的请求进行响应。后端主要分为servlet层、service层、dao层,除此外,系统使用Javabean技术对数据进行封装,servlet层主要实现对前端请求的响应,service层对数据流进行集中管理,dao层主要实现与数据库的交互,包括对数据库的查询、更新、插入等操作。前后端代码结构如下图:
2、 前端设计
页面大部分采用div+css进行开发,主要包括系统主页、商品列表页、商品详情页、用户登录页、用户注册页、用户个人中心页(查看订单、查看购物车等)、管理员登录页、系统管理页(商品添加、查看用户订单)等;页面效果如下:
<1> 主页:
页面效果说明:此页面为用户进入系统时初始展示的页面,页面的相关商品信息均由数据库中加载并显示在页面上,此页面中,提供用户注册及登录的接口,页头会根据用户是否登录显示用户信息,登录后效果如下:
<2> 商品详情页:(用户点击某一商品时,跳转至商品详情页,此操作无需登录)
页面说明:此页面由用户点击某一商品区域后,根据用户选中的商品进入此页面,并展示用户选中商品的详细信息,此页面无需认证用户信息即可进入。在此页面中,用户可以查看商品信息,把商品加入购物车,购买商品等操作,当用户点击加入购物车或购买商品时,系统会检查用户是否登录,如未登录会跳转至用户登录页面,引导用户成功登录后再返回此页面。
<3>、商品列表页
页面说明:此页面主要通过各页面的搜索框进入,用户在各页面搜索框中输入需要查询的商品,点击后跳转至该页面,并显示搜索到的所有商品信息,后台根据搜索内容进行模糊搜索,把搜素到的商品按匹配程度进行展示。此页面同样不需要认证用户身份,加入购物车及收藏时会引导用户登录。
<4>、用户登录页
页面说明:此页面为用户登录页,提供用户注册接口及管理员登录唯一接口,用户输入登录信息中,均使用正则表达式对输入进行验证,同时需要输入验证码信息,只有输入都合法的情况下,系统才会继续提交信息到后台进行身份验证,前端通过后端返回的信息确定用户身份的合法性,合法则分配用户相应权限。
<5>、用户注册页
页面说明:此页面为用户注册页面,用户输入个人相关必要信息进行注册,手机号码为用户在系统中的唯一凭证(一个手机号码只能注册一个账户),在用户输入信息过程中,系统实时进行监控,以判断用户输入的信息合法性,不合法并给出相应提示,如下:
在用户输入手机号码后,系统向后端发送请求,检查该手机号是否注册,并提供用户以提示信息,优化用户体验,提高用户注册效率。
用户注册成功或者遇到其他错误而导致注册失败时,均会跳转至注册结果提示页,并引导用户进行下一步操作,具体页面如下:
<6>、用户个人中心页
页面说明:此页面需要认证用户信息,只有登录的用户才能进入此页面,为防止非法用户通过直接输入该页面地址进入,特别在页面加载中对用户进行验证,非法用户强行进入时,系统会自动转至系统首页,以提高系统的安全性。合法用户进入后,可以通过点击左边的导航栏查看用户个人的相关信息,系统通过用户选中项,向后端发送请求,并把相关信息返回至用户界面。
<7>、管理员登录页
页面说明:此页面提供管理员登录页面,与用户登录相似,系统同样会对输入信息进行校验,管理员帐号不能通过注册获得,只有通过内部人员才能拥有管理员账户。
<8>、管理员管理页面
页面说明:同样,管理员管理页面同样需要认证登入者信息,非法用户也会自动转移到其它不需要认证身份的页面中,以保护系统的信息安全。管理员可以通过左边的导航栏,展开相应的子菜单,选中并进入查看相关信息,对系统进行管理。
3、 前端代码设计
前端主要采用了jquery框架进行开发,使用ajax技术向后端发起请求,使用json数据格式对数据进行处理。前端代码结构如下:
页面主要为.html页面,css样式文件及js文件实现分离,每个html页面对应一个.css文件合.js文件,css文件对页面布局进行渲染,js文件主要实现页面的动态效果以及使用ajax技术向后端发起请求等。
前端代码通过对页面文件、样式文件及脚本文件实行的分理,大大提高了代码的可读性及代码的维护性。在前端代码中,一些需要大量重用的代码集中成一个工具文件,使用时只需要调用相关函数即可,减少了代码量,使得代码更加清晰。
特色代码文件:Tools.js
//string 转 JSON
function change(str) {
var reg = new RegExp("=",“g”);
str = str.replace(reg,"?;
var str1 = “”;
for (var i = 0; i < str.length; i++) {
if (str[i] == “:” || str[i] == “,”) {
str1 = str1 + “’” + str[i] + “’”;
if(str[i] == “,”){
i+=1;
}
} else {
if (str[i] == “{” || str[i] == “}”) {
if (str[i] == “{”) {
str1 = str1 + str[i] + “’”;
} else {
str1 = str1 + “’” + str[i];
break;
}
} else {
if(str[i] == “”){
continue;
}else{
str1 = str1 + str[i];
}
}
}
// console.log(“str=” + str[i] + " str1=" + str1);
}
// console.log(encodeURIComponent(str1)); //查看编码序列
// return JSON.parse(str1);
str1 = eval("(" + str1 + “)”); //转换JSON对象
// alert(typeof str1);
// alert(“pet_name=”+str1.pet_name)
return str1;
}
//封装Cookie
function SetCookie(json) {
console.log(json);
var cookie = “”;
var time = new Date();
time.setTime(time.getTime()+72460601000); //设定七天有效期
for(var key in json){
cookie = key+"="+json[key]+";expires="+time.toUTCString()+";path=/";
document.cookie = cookie;
}
console.log(document.cookie);
}
//查找cookie中的特定值
function getCookie(key){
var arrcookie = document.cookie.split("; “);//分割
//遍历匹配
for ( var i = 0; i < arrcookie.length; i++) {
var arr = arrcookie[i].split(”=");
if (arr[0] == key){
return arr[1];
break;
}else {
continue;
}
}
}
//删除cookie
function deleteCookie(key) {
var time = new Date(); //获取时间
time.setTime(time.getTime() - 12460601000); //设置cookie有效时间为-1天,已到达删除cookie的目的
var value = getCookie(key);
if(value != null) {
document.cookie= key + “=”+value+";expires="+time.toUTCString()+";path=/";
// document.cookie= key + “=”+value+";expires=-1;path:/";
}
}
//批量删除cookie
function deleteCookieGroup(arr) {
for(var temp in arr){
deleteCookie(arr[temp]);
}
}
//string转换arrString
function transitionArrString(data) {
data = data.replace("[","");
data = data.replace("]","");
var arrData = new Array();
var count = 0;
for (var i = 0; i < data.length; i++) {
if (data[i] == “}”) {
arrData[count] = arrData[count] + data[i];
count++;
} else {
if ((data[i] == “,” && data[i + 1] == “{”) || data[i] == “”) {
continue;
} else {
if (data[i] == “{”) {
arrData[count] = “”;
}
arrData[count] = arrData[count] + data[i];
}
}
}
// arrData.pop();
return arrData;
}
//数组转json数组
function arrToJson(data) {
data.forEach(function (temp) {
change(temp);
})
}
4、 后端设计
后端主要使用servlet响应前端请求,后端主要分为四个模块,分别为servlet模块、service模块、dao模块、beans模块。
Servlet模块主要用于响应前端请求,是对前端数据的初次处理,每一个前端请求都对应一个servlet,每个servlet响应不同的请求,servlet层对各种请求进行了划分,便于代码的维护,数据在servlet层进行简单处理后,交由service层对数据进一步进行处理,按请求的需要分配不同的函数,每个函数同样对应dao层的独立一个类,分别实现不同的对数据库的操作,dao层为对数据库的独立操作,避免了用户请求直接访问数据库造成对数据库的安全性减低,dao层实现特定对数据库的不同操作,使代码的独立性得到增强;beans层主要作为数据封装的工具,常常应用于servlet层及dao层对数据的封装,一般来说,每一个bean对应一个数据库表的信息,当然,未来满足特殊的需求,往往也存在一个bean中存在数各数据库表中的字段信息。
数据流图如下:
在后端的设计实现中,数据的传输及对数据库的操作自然时最多的,为了减少代码量,提高代码的重用性,同样对常用的代码进行封装,每次使用时,直接调用该代码块封装函数即可,在数据库操作中,主要封装了JDBCUtil类用于获取数据库连接对象,相关代码如下:
package cn.gzhu.edu.dao;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JDBCUtils {
private JDBCUtils(){}
private static Connection con;
static{
try{
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/shopping";
String username="root";
String password="123";
con = DriverManager.getConnection(url, username, password);
}catch(Exception ex){
// throw new RuntimeException(ex+“连接数据库失败”);
ex.printStackTrace();
}
}
public static Connection getConnection(){
return con;
}
public static void close(Connection con,Statement stat){
if(stat!=null){
try{
stat.close();
}catch(SQLException ex){}
}
if(con!=null){
try{
con.close();
}catch(SQLException ex){}
}
}
public static void close(Connection con,Statement stat , ResultSet rs){
if(rs!=null){
try{
rs.close();
}catch(SQLException ex){}
}
if(stat!=null){
try{
stat.close();
}catch(SQLException ex){}
}
if(con!=null){
try{
con.close();
}catch(SQLException ex){}
}
}
}
在servlet层进行对数据到前端的传送中,同样封装了数据传输相关类进行操作,相关代码如下:
package cn.gzhu.edu.servlet;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
/**
- 将后台处理完的结果写回前端页面,如jsp页面;
- 或者可用于在ajax异步调用后台方法,该方法处理完相应业务逻辑之后将结果返回,这个结果即通过这个工具类实现
*/
public class ResponseJsonUtils {
public static void json(HttpServletResponse response, Object o) throws Exception {
response.setContentType(“text/html;charset=utf-8”);
PrintWriter out = response.getWriter();
// out.println(o.toString());
// System.out.println(o.toString());
out.write(o.toString());
out.flush();
out.close();
// System.out.println(“怕是你没有发信息出去”);
}
}
5、 数据库设计
本项目中,主要有四个表:商品信息表、管理员信息表、用户信息表、订单相关数据表等,各表及表结构如下:
Book表:
序号 字段名 数据类型 长度 主外键 是否可空 描述
1 B_id varchar 50 主键 否 商品编号
2 B_name varchar 100 否 商品名称
3 B_describe varchar 300 否 商品描述
4 B_publish_company varchar 100 否 出版社
5 B_publish_time varchar 50 否 出版时间
6 B_author varchar 50 否 作者
7 B_isbn varchar 20 否 ISBN码
8 B_newprice varchar 20 否 现价
9 B_oldprice varchar 20 否 原价
10 B_photo_1 varchar 30 商品图片
11 B_photo_2 varchar 30 商品图片
12 B_photo_3 varchar 30 商品图片
13 B_photo_4 varchar 30 商品图片
14 B_photo_5 varchar 30 商品图片
Users表:
序号 字段名 数据类型 长度 主外键 是否可空 描述
1 Upet_name varchar 20 否 昵称
2 Uphone varchar 20 主键 否 手机号码
3 upsw varchar 50 否 密码
4 usex varchar 2 性别
5 uage smallint 4 年龄
6 uaddress varchar 100 地址
7 Ujoin_time varchar 20 否 注册时间
manage表:
序号 字段名 数据类型 长度 主外键 是否可空 描述
1 M_name varchar 20 主键 否 管理员姓名
2 M_id varchar 20 否 管理员id
3 M_password varchar 20 否 密码
Shoppingcart表:
序号 字段名 数据类型 长度 主外键 是否可空 描述
1 Order_id varchar 50 主键 否 订单编号
2 B_id varchar 50 外键 否 商品编号
3 uphone varchar 20 外键 否 用户编号
4 Order_num int 4 否 数量
5 Order_status int 4 否 订单状态(0 已删除 1 购物车 2 已购买 3收藏)
6、 web.xml配置
在系统开发中,正确配置web.xml文件是实现前后端信息交互的关键,也是大部分错误发生的关键原因之一,一些常见的400、403、404等异常错误信息均有可能由于web.xml文件的配置错误而导致的,因此,正确配置web.xml非常重要,系统web.xml完整配置如下:
html/index.html
html/Reg.html
default.htm
default.jsp
<servlet>
<servlet-name>loginCheck</servlet-name>
<servlet-class>cn.gzhu.edu.servlet.LoginCheckServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>loginCheck</servlet-name>
<url-pattern>/loginCheck</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>register</servlet-name>
<servlet-class>cn.gzhu.edu.servlet.RegisterServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>register</servlet-name>
<url-pattern>/register</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>phoneCheck</servlet-name>
<servlet-class>cn.gzhu.edu.servlet.PhoneCheckServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>phoneCheck</servlet-name>
<url-pattern>/phoneCheck</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>ManageLogin</servlet-name>
<servlet-class>cn.gzhu.edu.servlet.ManageLoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ManageLogin</servlet-name>
<url-pattern>/ManageLogin</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>AddBooks</servlet-name>
<servlet-class>cn.gzhu.edu.servlet.AddBooksServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AddBooks</servlet-name>
<url-pattern>/AddBooks</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>loadCommodity</servlet-name>
<servlet-class>cn.gzhu.edu.servlet.LoadCommodityServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>loadCommodity</servlet-name>
<url-pattern>/loadCommodity</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>loadBook</servlet-name>
<servlet-class>cn.gzhu.edu.servlet.LoadBookServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>loadBook</servlet-name>
<url-pattern>/loadBook</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>addShoppingCart</servlet-name>
<servlet-class>cn.gzhu.edu.servlet.AddShoppingCartServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>addShoppingCart</servlet-name>
<url-pattern>/addShoppingCart</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>loadShoppingCart</servlet-name>
<servlet-class>cn.gzhu.edu.servlet.LoadShoppingCardServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>loadShoppingCart</servlet-name>
<url-pattern>/loadShoppingCart</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>searchCommodity</servlet-name>
<servlet-class>cn.gzhu.edu.servlet.SearchCommodityServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>searchCommodity</servlet-name>
<url-pattern>/searchCommodity</url-pattern>
</servlet-mapping>