1.1 研究目的和意义
随着市场经济发展,尤其是我国加入WTO ,融入经济全球化潮流,已进入国内外市场经济发展新时期,音乐与市场联系越来越紧密,我国音乐和网上业务也进入新历史发展阶段。为了更好地服务于市场,推进网上业务现代化进程,音乐信息体系建设已迫在眉睫。随着电子商务在批发市场运用深化,一部分批发市场“蒸发”了,悄然退出市场、使有形市场和无形市场相结合从而产生一种新模式。对绝大多数市场来说,在组织创新上,当前最易采取形式是有形市场与无形市场相结合的方式。可以充分利用有形市场的优势,创办网上音乐销售市场,搭建网上交易平台为市场经营者建立网上音乐专辑,进行产品宣传,引导经营者开展网上交易,实行与现货交易并行的电子商务模式。使电子商务音乐专辑网站的发展成为必然。
1.2 研究的内容
该网上音乐市场系统可以注册用户, 用户注册完以后可以用相应的用户名和密码进行登陆,用户进入系统后,可以浏览音乐专辑的一些详细的信息。后台的管理员能够对网站的音乐商品信息进行管理,同时也可以对用户就行管理。没有注册的用户可以查看一些音乐专辑信息,但是如果想获得更加详细的信息或者购买音乐专辑,用户就必须要进行相应的注册或登录才能够得到更加详细的音乐商品信息以便于购买该音乐专辑
1.3可行性研究设计
此系统需要java面向对象编程基础,数据库应用知识以及功能分析。根据目前阶段所掌握的知识,根据这学期以及之前学习掌握的java编程知识和数据库应用知识以及前端知识做出一个这样的基于Javaweb、springboot轻量级框架网页版的网上音乐专辑商城系统。
1.4社会可行性
在互联网技术高速发展的今天,通过互联网的传播会让企业更容易的创造更多的经 济效益,通过网上音乐专辑平台销售,有了更大的市场,在这样一个大环境下把资源统筹规化起来,就会获得高效的收益。
1.5相关技术说明
spring
Spring框架是Java平台上的一种开源应用框架,提供具有控制反转特性的容器。尽管Spring框架自身对编程模型没有限制,但其在Java应用中的频繁使用让它备受青睐,以至于后来让它作为EJB(EnterpriseJavaBeans)模型的补充,甚至是替补。Spring框架为开发提供了一系列的解决方案,比如利用控制反转的核心特性,并通过依赖注入实现控制反转来实现管理对象生命周期容器化,利用面向切面编程进行声明式的事务管理,整合多种持久化技术管理数据访问,提供大量优秀的Web框架方便开发等等。Spring框架具有控制反转(IOC)特性,IOC旨在方便项目维护和测试,它提供了一种通过Java的反射机制对Java对象进行统一的配置和管理的方法。Spring框架利用容器管理对象的生命周期,容器可以通过扫描XML文件或类上特定Java注解来配置对象,开发者可以通过依赖查找或依赖注入来获得对象。Spring框架具有面向切面编程(AOP)框架,SpringAOP框架基于代理模式,同时运行时可配置;AOP框架主要针对模块之间的交叉关注点进行模块化。Spring框架的AOP框架仅提供基本的AOP特性,虽无法与AspectJ框架相比,但通过与AspectJ的集成,也可以满足基本需求。Spring框架下的事务管理、远程访问等功能均可以通过使用SpringAOP技术实现。Spring的事务管理框架为Java平台带来了一种抽象机制,使本地和全局事务以及嵌套事务能够与保存点一起工作,并且几乎可以在Java平台的任何环境中工作。Spring集成多种事务模板,系统可以通过事务模板、XML或Java注解进行事务配置,并且事务框架集成了消息传递和缓存等功能。Spring的数据访问框架解决了开发人员在应用程序中使用数据库时遇到的常见困难。它不仅对Java:JDBC、iBATS/MyBATIs、Hibernate、Java数据对象(JDO)、ApacheOJB和ApacheCayne等所有流行的数据访问框架中提供支持,同时还可以与Spring的事务管理一起使用,为数据访问提供了灵活的抽象。Spring框架最初是没有打算构建一个自己的WebMVC框架,其开发人员在开发过程中认为现有的StrutsWeb框架的呈现层和请求处理层之间以及请求处理层和模型之间的分离不够,于是创建了SpringMVC。
SpringBoot
SpringBoot是由Pivotal团队在2013年开始研发、2014年4月发布第一个版本的全新开源的轻量级框架。它基于Spring4.0设计,不仅继承了Spring框架原有的优秀特性,而且还通过简化配置来进一步简化了Spring应用的整个搭建和开发过程。另外SpringBoot通过集成大量的框架使得依赖包的版本冲突,以及引用的不稳定性等问题得到了很好的解决。
SpringBoot所具备的特征有:
(1)可以创建独立的Spring应用程序,并且基于其Maven或Gradle插件,可以创建可执行的JARs和WARs;
(2)内嵌Tomcat或Jetty等Servlet容器;
(3)提供自动配置的“starter”项目对象模型(POMS)以简化Maven配置;
(4)尽可能自动配置Spring容器;
(5)提供准备好的特性,如指标、健康检查和外部化配置;
SpringBoot框架中还有两个非常重要的策略:开箱即用和约定优于配置。开箱即用,Outofbox,是指在开发过程中,通过在MAVEN项目的pom文件中添加相关依赖包,然后使用对应注解来代替繁琐的XML配置文件以管理对象的生命周期。这个特点使得开发人员摆脱了复杂的配置工作以及依赖的管理工作,更加专注于业务逻辑。约定优于配置,Convention over configuration,是一种由SpringBoot本身来配置目标结构,由开发者在结构中添加信息的软件设计范式。这一特点虽降低了部分灵活性,增加了BUG定位的复杂性,但减少了开发人员需要做出决定的数量,同时减少了大量的XML配置,并且可以将代码编译、测试和打包等工作自动化。
SpringBoot应用系统开发模板的基本架构设计从前端到后台进行说明:前端常使用模板引擎,主要有FreeMarker和Thymeleaf,它们都是用Java语言编写的,渲染模板并输出相应文本,使得界面的设计与应用的逻辑分离,同时前端开发还会使用到Bootstrap、AngularJS、JQuery等;在浏览器的数据传输格式上采用Json,非xml,同时提供RESTfulAPI;SpringMVC框架用于数据到达服务器后处理请求;到数据访问层主要有Hibernate、MyBatis、JPA等持久层框架;数据库常用MySQL;开发工具推荐IntelliJIDEA。
jQuery
jQuery是一个快速、简洁的JavaScript框架,是继Prototype之后又一个优秀的JavaScript代码库(或JavaScript框架)。jQuery设计的宗旨是“write Less,Do More”,即倡导写更少的代码,做更多的事情。它封装JavaScript常用的功能代码,提供一种简便的JavaScript设计模式,优化HTML文档操作、事件处理、动画设计和Ajax交互。
jQuery的核心特性可以总结为:具有独特的链式语法和短小清晰的多功能接口;具有高效灵活的css选择器,并且可对CSS选择器进行扩展;拥有便捷的插件扩展机制和丰富的插件。jQuery兼容各种主流浏览器,如IE 6.0+、FF 1.5+、Safari 2.0+、Opera 9.0+等
Mysql
MySQL 是一款安全、跨平台、高效的,并与 PHP、Java 等主流编程语言紧密结合的数据库系统。该数据库系统是由瑞典的 MySQL AB 公司开发、发布并支持,由 MySQL 的初始开发人员 David Axmark 和 Michael Monty Widenius 于 1995 年建立的。
MySQL 的象征符号是一只名为 Sakila 的海豚,代表着 MySQL 数据库的速度、能力、精确和优秀本质。
图:MySQL 图标
目前 MySQL 被广泛地应用在 Internet 上的中小型网站中。由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,使得很多公司都采用 MySQL 数据库以降低成本。
MySQL 数据库可以称得上是目前运行速度最快的 SQL 语言数据库之一。除了具有许多其他数据库所不具备的功能外,MySQL 数据库还是一种完全免费的产品,用户可以直接通过网络下载 MySQL 数据库,而不必支付任何费用。
MySQL 特点
下面总结了一下 MySQL 具备的特点。
1) 功能强大
MySQL 中提供了多种数据库存储引擎,各引擎各有所长,适用于不同的应用场合,用户可以选择最合适的引擎以得到最高性能,可以处理每天访问量超过数亿的高强度的搜索 Web 站点。MySQL5 支持事务、视图、存储过程、触发器等。
2) 支持跨平台
MySQL 支持至少 20 种以上的开发平台,包括 Linux、Windows、FreeBSD 、IBMAIX、AIX、FreeBSD 等。这使得在任何平台下编写的程序都可以进行移植,而不需要对程序做任何的修改。
3) 运行速度快
高速是 MySQL 的显著特性。在 MySQL 中,使用了极快的 B 树磁盘表(MyISAM)和索引压缩;通过使用优化的单扫描多连接,能够极快地实现连接;SQL 函数使用高度优化的类库实现,运行速度极快。
4) 支持面向对象
PHP 支持混合编程方式。编程方式可分为纯粹面向对象、纯粹面向过程、面句对象与面向过程混合 3 种方式。
5) 安全性高
灵活和安全的权限与密码系统,允许基本主机的验证。连接到服务器时,所有的密码传输均采用加密形式,从而保证了密码的安全。
6) 成本低
MySQL 数据库是一种完全免费的产品,用户可以直接通过网络下载。
7) 支持各种开发语言
MySQL 为各种流行的程序设计语言提供支持,为它们提供了很多的 API 函数,包括 PHP、ASP.NET、Java、Eiffel、Python、Ruby、Tcl、C、C++、Perl 语言等。
8) 数据库存储容量大
MySQL 数据库的最大有效表尺寸通常是由操作系统对文件大小的限制决定的,而不是由 MySQL 内部限制决定的。InnoDB 存储引擎将 InnoDB 表保存在一个表空间内,该表空间可由数个文件创建,表空间的最大容量为 64TB,可以轻松处理拥有上千万条记录的大型数据库。
9) 支持强大的内置函数
PHP 中提供了大量内置函数,几乎涵盖了 Web 应用开发中的所有功能。它内置了数据库连接、文件上传等功能,MySQL 支持大量的扩展库,如 MySQLi 等,可以为快速开发 Web 应用提供便利。
数据库的应用
数据库是计算机应用系统中的一种专门管理数据资源的系统。数据有多种形式,如文字、数码、符号、图形、图像及声音等,数据是所有计算机系统所要处理的对象。我们所熟知的一种处理办法是制作文件,即将处理过程编成程序文件,将所涉及的数据按程序要求组成数据文件,再用程序来调用,数据文件与程序文件保持着一定的关系。
在计算机应用迅速发展的情况下,这种文件式管理方法便显出它的不足。比如,它使得数据通用性差、不便于移植、在不同文件中存储大量重复信息、浪费存储空间、更新不便等。
而数据库系统便能解决上述问题。数据库系统不从具体的应用程序出发,而是立足于数据本身的管理,它将所有数据保存在数据库中,进行科学的组织,并借助于数据库管理系统,以它为中介,与各种应用程序或应用系统接口,使之能方便地使用数据库中的数据。
其实简单地说,数据库就是一组经过计算机整理后的数据,存储在一个或多个文件中,而管理这个数据库的软件就称为数据库管理系统。一般一个数据库系统(Database System)
可以分为数据库(Database)与数据管理系统(Database Management System,DBMS)两个部分。主流的数据库软件有 Oracle、Informix、Sybase、SQL Server、PostgreSQL、MySQL、Access、FoxPro 和 Teradata 等等。
数据库在 Web 开发中的重要地位
归根结底,动态网站都是对数据进行操作,我们平时浏览网页时,会发现网页的内容会经常变化,而页面的主体结构框架没变,新闻就是一个典型。这是因为我们将新闻存储在了数据库中,用户在浏览时,程序就会根据用户所请求的新闻编号,将对应的新闻从数据库中读取出来,然后再以特定的格式响应给用户。
Web 系统的开发基本上是离不开数据库的,因为任何东西都要存放在数据库中。所谓的动态网站就是基于数据库开发的系统,最重要的就是数据管理,或者说我们在开发时都是在围绕数据库在写程序。所以作为一个 Web 程序员,只有先掌握一门数据库,才可能去进行软件开发。
- 需求分析
2.1系统功能概述
1) 用户注册和登录登录功能
2) 用户信息的管理
3) 用户音乐商品的操作
4) 用户购物车的管理
5) 用户订单管理操作管理
6)音乐专辑类型的管理、添加、修改、删除操作
7)网页音乐商品的预览、查看等
8)注销退出登录
2.2系统运行环境
使用 Windows7作为开发的系统。
JavaJDK1.8环境配置、
Java运行在idea软件上,
数据库用mysql5版本数据库、
数据库采用Nacicat Mysql可视化工具、
基于主流的谷歌浏览器运行展示以及F12控制台调试样式、
- 系统设计
3.1系统设计
系统主要设计采用Java语言开发、采用springboot为后台框架、数据库框架采用mybatis、前端采用jquery、layui框架等
主要模块设计如下:
3.1.1客户端主要设计
(1) 用户注册和登录登录功能:
1用户的注册功能 : 访问网站的人根据网站的提示注册自己的账户
2用户的登录功能 : 用户可以输入用户名和密码进行登录操作,当没有该账户的时 候,提示错误,用户必须通过注册完成或者从数据库中获取才能进行会员权限级别的操 作。登录成功之后可以购买音乐商品,查询订单的详细信息
(2) 、个人信息的管理:
1用户信息的修改操作,其中包括用户名、密码、性别、联系方式 e-mail 和个人介 绍等用户信息的修改操作。2订单管理操作:订单只能查询和删除操作,不能有修改操作,修改操作是属于管理员的权限。
3用户退出操作:当点击用户退出时,就会退出当前用户的登录状态,恢复到游客 状态。
(3) 、音乐专辑商品的操作:
1.音乐专辑列表展示:在全部列表中会有很多分列表目录,这些目录都是不同的种类, 当我们点击不同的目录,就会查询不同的音乐专辑物品。
2.音乐专辑详细信息展示:会根据该目录下的音乐专辑物品类型展示出全部的音乐专辑物品。包括信息包 括音乐专辑物品的图片、价格、售价等信息。这些信息都不带有分页,如果音乐专辑物品列表下的商品很 多,就会分很多页进行分页查询。
(4) 、购物车的管理操作:
①显示音乐专辑物品信息:当我们一进入购物车页面,就会显示出音乐专辑物品的详细信息,以及购 物车界面的功能信息。
2.删除购物车中的音乐专辑物品:当我们点击删除时,会弹出一个提示框提示我们是否删除 音乐专辑物品,当点击‘确定’,就删除成功,点击 ‘取消’,对话框消失并且没有任何操作执行。
3.4主流程描述
- 5源码架构
- 系统实现
4.1 程序主要类
4.1.1用户管理员类
@Data
@Entity
public class AdminUser implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue
@Column
private Integer id;
@Column(nullable = false)
private String username;
@Column
private String password;
public AdminUser(Integer id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
public AdminUser() {
super();
}
4.1.4音乐商品分类
/**
* 分类
*/
@Entity
public class Classification implements Serializable {
@Id
@GeneratedValue
@Column
private Integer id;
/**
* 上级分类Id
*/
@Column
private Integer parentId;
/**
* 分类名称
*/
@Column
private String cname;
/**
* 类型 1一级分类 2二级分类
*/
@Column
private Integer type;
4.1.4音乐商品订单类
/**
* 订单
*/
@Entity
@Table(name = "`order`")
public class Order implements Serializable {
@Id
@GeneratedValue
@Column
private Integer id;
/**
* 订单总价
*/
@Column
private Double total;
/**
* 订单状态 1:未付款 2:等待发货 3:等待收货 4:订单完成
*/
@Column
private Integer state;
/**
* 订单时间
*/
@Column
private Date orderTime;
/**
* 收货人姓名
*/
@Column(name = "`name`")
private String name;
/**
* 收货人联系电话
*/
@Column
private String phone;
/**
* 收货地址
*/
@Column
private String addr;
/**
* 用户Id
*/
@Column
private Integer userId;
4.1.4音乐商品订单详情类
/**
* 订单项
*/
@Entity
public class OrderItem implements Serializable {
@Id
@GeneratedValue
@Column
private Integer id;
/**
* 订单Id
*/
@Column
private Integer orderId;
/**
* 商品Id
*/
@Column
private Integer productId;
/**
* 数量
*/
@Column
private Integer count;
/**
* 总价
*/
@Column
private Double subTotal;
@Transient
private Product product;
4.1.4音乐商品详情类
@Entity
@JsonIgnoreProperties({ "handler","hibernateLazyInitializer" })
public class Product implements Serializable {
@Id
@GeneratedValue
@Column
private Integer id;
/**
* 商品标题
*/
@Column
private String title;
/**
* 市场价
*/
@Column
private Double marketPrice;
/**
* 商城价
*/
@Column
private Double shopPrice;
/**
* 主图
*/
@Column
private String image;
/**
* 描述
*/
@Column(name = "`desc`", columnDefinition = "text")
private String desc;
/**
* 是否热门商品
*/
@Column
private Integer isHot;
/**
* 二级分类Id
*/
@Column
private Integer csid;
/**
* 商品创建日期
*/
@Column
private Date pdate;
4.1.4用户客户类
@Entity
public class User implements Serializable {
@Id
@GeneratedValue
@Column
private Integer id;
/**
* 用户名
*/
@Column
private String username;
/**
* 密码
*/
@Column
private String password;
/**
* 姓名
*/
@Column
private String name;
/**
* 邮件
*/
@Column
private String email;
/**
* 电话
*/
@Column
private String phone;
/**
* 地址
*/
@Column
private String addr;
4.3系统功能主要实现模块截图
4.3.1登陆页面
用户输入账号和密码和登录进行登录
4.3.1登录前端代码:
function login() {
var username = $("[name='username']").val();
var password = $("[name='password']").val();
if (!username || !password) {
alert("用户名密码不能为空!");
return;
}
$.ajax({
type: "post",
url: "login.do",
data: {"username": username, "pwd": password},
success: function (data) {
console.log(data);
if (data.state == 0) {
window.location.href = "toIndex.html";
} else {
alert(data.message);
}
}
});
4.3.2注册页面:
/**
* 注册
*/
@RequestMapping("/register.do")
public void register(String username,
String password,
String name,
String phone,
String email,
String addr,
HttpServletResponse response) throws IOException {
User user = new User();
user.setUsername(username);
user.setPhone(phone);
user.setPassword(password);
user.setName(name);
user.setEmail(email);
user.setAddr(addr);
userService.create(user);
// 注册完成后重定向到登录页面
response.sendRedirect("/mall/user/toLogin.html");
}
4.3.2 系统功能截图
系统主页面是高校跳蚤市场商品信息的展示、右侧上方是用户功能操作、没有登录的用户可以选择登录或注册操作才可以对商品进行购买、加入购物车等操作
查看热门音乐专辑物品
查看最新音乐专辑物品
用户可以查看我的订单信息以及我的购物车
查看我的购物车
后台管理员用户管理、可以对客户用户进行添加、编辑、删除操作
编辑用户信息
编辑音乐专辑商品分类列表
编辑商品二级分类列表
编辑音乐专辑商品具体信息
4.3.4部分关键源码展示:
4.3.4.1登录:
/**
* 登录
*
* @param username
* @param password
*/
@RequestMapping("/login.do")
public void login(String username,
String password,
HttpServletRequest request,
HttpServletResponse response) throws IOException {
User user = userService.checkLogin(username, password);
if (user != null) {
//登录成功 重定向到首页
request.getSession().setAttribute("user", user);
response.sendRedirect("/mall/index.html");
} else {
throw new LoginException("登录失败! 用户名或者密码错误");
}
}
4.3.4.2 全局配置文件:
# \u8BBF\u95EE\u8DEF\u5F84\uFF0C\u7AEF\u53E3\u914D\u7F6E
server.context-path=/mall
server.port=8081
# \u6587\u4EF6\u4E0A\u4F20\u914D\u7F6E
spring.http.multipart.enabled=true
spring.http.multipart.max-file-size=100MB
spring.http.multipart.max-request-size=100MB
logging.level.priv.jesse.mall=DEBUG
# \u914D\u7F6E\u8F6Cjson\u7684\u65F6\u95F4\u683C\u5F0F
spring.jackson.time-zone=GMT+8
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
# jdbc\u8FDE\u63A5\u914D\u7F6E
# mysql
#spring.datasource.url=jdbc:mysql://active.iceslurry.xyz/mall?useSSL=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull
#spring.datasource.username=root
#spring.datasource.password=123456
#spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#H2
spring.datasource.url=jdbc:mysql://localhost:3307/mall?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=crit@2019
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#spring.h2.console.settings.web-allow-others=false
#spring.h2.console.path=/h2-console
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
#thymeleaf \u6A21\u677F\u5F15\u64CE\u8BBE\u7F6E
spring.thymeleaf.mode=HTML5
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.content-type=text/html
##\u5F00\u53D1\u65F6\u5173\u95ED\u7F13\u5B58,\u4E0D\u7136\u6CA1\u6CD5\u770B\u5230\u5B9E\u65F6\u9875\u9762
spring.thymeleaf.cache=false
##################### jpa hibernate \u914D\u7F6E #########################
spring.jpa.show-sql=false
spring.jpa.database=mysql
spring.jpa.properties.hibernate.format_sql=false
spring.jpa.generate-ddl=true
# \u6700\u5E38\u7528\u7684\u5C5E\u6027\uFF0C\u7B2C\u4E00\u6B21\u52A0\u8F7Dhibernate\u65F6\u6839\u636Emodel\u7C7B\u4F1A\u81EA\u52A8\u5EFA\u7ACB\u8D77\u8868\u7684\u7ED3\u6784\uFF08\u524D\u63D0\u662F\u5148\u5EFA\u7ACB\u597D\u6570\u636E\u5E93\uFF09\uFF0C
# \u4EE5\u540E\u52A0\u8F7Dhibernate\u65F6\u6839\u636Emodel\u7C7B\u81EA\u52A8\u66F4\u65B0\u8868\u7ED3\u6784\uFF0C\u5373\u4F7F\u8868\u7ED3\u6784\u6539\u53D8\u4E86\u4F46\u8868\u4E2D\u7684\u884C\u4ECD\u7136\u5B58\u5728\u4E0D\u4F1A\u5220\u9664\u4EE5\u524D\u7684\u884C\u3002
# \u8981\u6CE8\u610F\u7684\u662F\u5F53\u90E8\u7F72\u5230\u670D\u52A1\u5668\u540E\uFF0C\u8868\u7ED3\u6784\u662F\u4E0D\u4F1A\u88AB\u9A6C\u4E0A\u5EFA\u7ACB\u8D77\u6765\u7684\uFF0C\u662F\u8981\u7B49\u5E94\u7528\u7B2C\u4E00\u6B21\u8FD0\u884C\u8D77\u6765\u540E\u624D\u4F1A\u3002
spring.jpa.hibernate.ddl-auto=update
##################################################################
##################druid\u6570\u636E\u5E93\u8FDE\u63A5\u6C60\u914D\u7F6E############################
#\u914D\u7F6E\u521D\u59CB\u5316\u5927\u5C0F\uFF0C\u6700\u5C0F\uFF0C\u6700\u5927
spring.datasource.druid.initial-size=1
spring.datasource.druid.max-active=20
spring.datasource.druid.min-idle=1
#\u914D\u7F6E\u83B7\u53D6\u8FDE\u63A5\u7B49\u5F85\u8D85\u65F6\u7684\u65F6\u95F4
spring.datasource.druid.max-wait=60000
#\u914D\u7F6E\u95F4\u9694\u591A\u4E45\u624D\u8FDB\u884C\u4E00\u6B21\u68C0\u6D4B\uFF0C\u68C0\u6D4B\u9700\u8981\u5173\u95ED\u7684\u7A7A\u95F2\u8FDE\u63A5\uFF0C\u5355\u4F4D\u662F\u6BEB\u79D2
spring.datasource.druid.time-between-eviction-runs-millis=60000
#\u914D\u7F6E\u4E00\u4E2A\u8FDE\u63A5\u5728\u6C60\u4E2D\u6700\u5C0F\u751F\u5B58\u7684\u65F6\u95F4\uFF0C\u5355\u4F4D\u662F\u6BEB\u79D2
spring.datasource.druid.min-evictable-idle-time-millis=300000
spring.datasource.druid.validation-query=SELECT 'x'
spring.datasource.druid.test-on-borrow=false
spring.datasource.druid.test-on-return=false
spring.datasource.druid.test-while-idle=true
#\u6253\u5F00PSCache\uFF0C\u5E76\u4E14\u6307\u5B9A\u6BCF\u4E2A\u8FDE\u63A5\u4E0APSCache\u7684\u5927\u5C0F
#\u5982\u679C\u7528Oracle\uFF0C\u5219\u628ApoolPreparedStatements\u914D\u7F6E\u4E3Atrue\uFF0Cmysql\u53EF\u4EE5\u914D\u7F6E\u4E3Afalse\u3002\u5206\u5E93\u5206\u8868\u8F83\u591A\u7684\u6570\u636E\u5E93\uFF0C\u5EFA\u8BAE\u914D\u7F6E\u4E3Afalse\u3002
spring.datasource.druid.pool-prepared-statements=false
spring.datasource.druid.max-pool-prepared-statement-per-connection-size=20
#druid\u76D1\u63A7\u914D\u7F6E
spring.datasource.druid.filters=stat,slf4j
# WebStatFilter\u914D\u7F6E\uFF0C\u8BF4\u660E\u8BF7\u53C2\u8003Druid Wiki\uFF0C\u914D\u7F6E_\u914D\u7F6EWebStatFilter
spring.datasource.druid.web-stat-filter.enabled=true
spring.datasource.druid.filter.stat.log-slow-sql=true
spring.datasource.druid.filter.stat.slow-sql-millis=2000
# StatViewServlet\u914D\u7F6E\uFF0C\u8BF4\u660E\u8BF7\u53C2\u8003Druid Wiki\uFF0C\u914D\u7F6E_StatViewServlet\u914D\u7F6E
spring.datasource.druid.stat-view-servlet.enabled=true
spring.datasource.druid.stat-view-servlet.url-pattern=/druid/*
spring.datasource.druid.stat-view-servlet.reset-enable=true
spring.datasource.druid.stat-view-servlet.login-username=druid
spring.datasource.druid.stat-view-servlet.login-password=123456
# Spring\u76D1\u63A7\u914D\u7F6E\uFF0C\u8BF4\u660E\u8BF7\u53C2\u8003Druid Github Wiki\uFF0C\u914D\u7F6E_Druid\u548CSpring\u5173\u8054\u76D1\u63A7\u914D\u7F6E
spring.datasource.druid.aop-patterns=priv.jesse.mall.service.impl.*
# druid\u65E5\u5FD7\u8F93\u51FA
spring.datasource.druid.filter.slf4j.enabled=true
spring.datasource.druid.filter.slf4j.result-set-log-enabled=false
spring.datasource.druid.filter.slf4j.statement-create-after-log-enabled=false
spring.datasource.druid.filter.slf4j.statement-close-after-log-enabled=false
spring.datasource.druid.filter.slf4j.result-set-open-after-log-enabled=false
spring.datasource.druid.filter.slf4j.result-set-close-after-log-enabled=false
##################druid\u8FDE\u63A5\u6C60\u914D\u7F6E\u7ED3\u675F############################
4.3.4.3 上传文件:
/**
* 保存上传的文件
*
* @param file
* @return 文件下载的url
* @throws Exception
*/
public static String saveFile(MultipartFile file) throws Exception {
if (file == null || file.isEmpty())
return "";
File target = new File("file");
if (!target.isDirectory()) {
target.mkdirs();
}
String originalFilename = file.getOriginalFilename();
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(file.getBytes());
String fileName = (Helper.bytesToHex(md.digest(),0,md.digest().length-1)) + "." + getPostfix(originalFilename);
File file1 = new File(target.getPath() + "/" + fileName);
Files.write(Paths.get(file1.toURI()), file.getBytes(), StandardOpenOption.CREATE_NEW);
return "/mall/admin/product/img/" + fileName;
4.3.4.4代码主启动类:
/**
* 程序启动入口
*
* @ServletComponentScan 设置启动时spring能够扫描到我们自己编写的servlet和filter, 用于Druid监控
* @MapperScan("com.imlaidian.springbootdemo.dao") 扫描mybatis Mapper接口
* @EnableScheduling 启用定时任务
* @EnableTransactionManagement 开启事务
*
* @author hfb
* @date 2017/9/18 11:13
*/
@ServletComponentScan
@EnableConfigurationProperties
@EnableTransactionManagement
@SpringBootApplication
public class MallApplication {
public static void main(String[] args) {
SpringApplication.run(MallApplication.class, args);
}
}
4.3.4.5 权限控制器:
package priv.jesse.mall.filter;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
/**
* 权限拦截器
*
* @author hfb
* @date 2017/9/18
*/
@WebFilter
public class AuthorizationFilter implements Filter {
public AuthorizationFilter() {
}
private static final Logger LOGGER = LoggerFactory.getLogger(AuthorizationFilter.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
// 支持跨域访问
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept,X-Custom-Header");
response.setHeader("X-Powered-By", "SpringBoot");
if ("option".equalsIgnoreCase(request.getMethod())) {
responseJSON(response, new HashMap<>());
return;
}
//除了拦截login.html 其他html都拦截
StringBuffer url = request.getRequestURL();
//System.out.println(url);
String path = url.toString();
// 只拦截这些类型请求
if (path.endsWith(".do") || path.endsWith(".html")) {
// 登录,图片不拦截
if (path.endsWith("toLogin.html")
|| path.endsWith("toRegister.html")
|| path.endsWith("register.do")
|| path.endsWith("login.do")
|| path.endsWith("logout.do")
|| path.endsWith("error.html")
|| path.endsWith("checkUsername.do")
|| path.contains("/mall/admin/product/img/")
|| path.endsWith("index.html")
|| path.endsWith("classification/list.do")
|| path.contains("product")
|| path.contains("/mall/h2-console")) {
chain.doFilter(request, response);
} else {
processAccessControl(request, response, chain);
}
} else {
//其他静态资源都不拦截
chain.doFilter(request, response);
}
}
/**
* @param request
* @param response
* @param chain
* @throws IOException
* @throws ServletException
*/
private void processAccessControl(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
Object adminUser = request.getSession().getAttribute("login_user");
Object user = request.getSession().getAttribute("user");
String url = request.getRequestURL().toString();
if (url.indexOf("admin") != -1){
if (adminUser == null) {
response.sendRedirect("/mall/admin/toLogin.html");
}else {
chain.doFilter(request, response);
}
}else {
if (user == null) {
response.sendRedirect("/mall/user/toLogin.html");
}else {
chain.doFilter(request, response);
}
}
}
@Override
public void destroy() {
}
/**
* 返回JOSN数据格式
*
* @param response
* @param object
* @throws IOException
*/
public static void responseJSON(HttpServletResponse response, Object object) throws IOException {
response.setContentType("application/json;charset=utf-8");
response.setCharacterEncoding("UTF-8");
ObjectMapper mapper = new ObjectMapper();
if (object == null)
return;
String jsonStr = mapper.writeValueAsString(object);
OutputStream out = response.getOutputStream();
out.write(jsonStr.getBytes("UTF-8"));
out.flush();
}
}
4.4数据库表设计
4.4.0数据三范式:
一、第一范式
1NF是对属性的原子性,要求属性具有原子性,不可再分解;
二、第二范式
2NF是对记录的唯一性,要求记录有唯一标识,即实体的唯一性,
三、第三范式
3NF是对字段的冗余性,要求任何字段不能由其他字段派生出来,
数据库采用mysql5版本、满足数据库设计三范式。
编码采用utf8 -- UTF-8 Unicode
排序规则采用utf8_general_ci
4.4.1表ER图
4.4.2用户表设计
主要字段有:用户名、密码、邮箱、地址、个人信息、手机号等信息
4.4.3音乐商品分类表设计
主要字段有:id、上级id 商品分类名称、类型等终端
4.4.4用户订单表设计
主要字段有:id、客户收货地址、姓名、收货时间、手机号、状态、数据量、用户id等字段
4.4.5音乐商品表详情设计
主要字段有:id、商品id、备注、商品图片、商品价格、商品标题、商品描述、时间等
4.4.5音乐商品订单表设计
主要字段有:id、商品数量、订单id、商品id、总价等
4.4.6数据库sql文件
/*
Navicat MySQL Data Transfer
Source Server : test
Source Server Version : 50560
Source Host : localhost:3306
Source Database : musicmall
Target Server Type : MYSQL
Target Server Version : 50560
File Encoding : 65001
Date: 2021-03-23 21:14:32
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for admin_user
-- ----------------------------
DROP TABLE IF EXISTS `admin_user`;
CREATE TABLE `admin_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`password` varchar(255) DEFAULT NULL,
`username` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of admin_user
-- ----------------------------
INSERT INTO `admin_user` VALUES ('1', 'admin', 'admin');
INSERT INTO `admin_user` VALUES ('2', 'hfb', 'hfb');
-- ----------------------------
-- Table structure for classification
-- ----------------------------
DROP TABLE IF EXISTS `classification`;
CREATE TABLE `classification` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`cname` varchar(255) DEFAULT NULL,
`parent_id` int(11) DEFAULT NULL,
`type` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of classification
-- ----------------------------
INSERT INTO `classification` VALUES ('1', '运动', '0', '1');
INSERT INTO `classification` VALUES ('2', '轻音乐', null, '1');
INSERT INTO `classification` VALUES ('3', '经典老歌', null, '1');
INSERT INTO `classification` VALUES ('4', 'KTV金曲', null, '1');
INSERT INTO `classification` VALUES ('10', '流行运动', '1', '2');
INSERT INTO `classification` VALUES ('11', '电子运动', '2', '2');
INSERT INTO `classification` VALUES ('12', '舒缓', '2', '2');
INSERT INTO `classification` VALUES ('13', '放松', '2', '2');
INSERT INTO `classification` VALUES ('14', '古典', '2', '2');
INSERT INTO `classification` VALUES ('15', '80年代', '3', '2');
INSERT INTO `classification` VALUES ('16', '90年代', '3', '2');
INSERT INTO `classification` VALUES ('17', '70年代', '3', '2');
INSERT INTO `classification` VALUES ('18', '国语歌', '4', '2');
INSERT INTO `classification` VALUES ('19', '粤语歌', '4', '2');
INSERT INTO `classification` VALUES ('20', '粤语歌', '4', '2');
-- ----------------------------
-- Table structure for order
-- ----------------------------
DROP TABLE IF EXISTS `order`;
CREATE TABLE `order` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`addr` varchar(255) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`order_time` datetime DEFAULT NULL,
`phone` varchar(255) DEFAULT NULL,
`state` int(11) DEFAULT NULL,
`total` double DEFAULT NULL,
`user_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of order
-- ----------------------------
INSERT INTO `order` VALUES ('1', 'fjsdakl', '小明', '2021-03-23 19:23:48', '12345654', '4', '8888', '1');
INSERT INTO `order` VALUES ('2', 'kdls;ajfklafkasld', 'tom', '2021-03-23 19:23:48', '123456894', '3', '17998', '1');
INSERT INTO `order` VALUES ('3', 'ffggghhhhfdfhjhff', 'Catalina', '2021-03-23 19:23:48', '1234322313', '2', '6077', '1');
INSERT INTO `order` VALUES ('4', 'fdsakldfjasl;', 'tomcat', '2021-03-23 19:23:48', '1234567878', '4', '8999', '1');
INSERT INTO `order` VALUES ('5', 'Gggggggg', 'Hfb', '2021-03-23 19:23:48', '18679658549', '1', '5999', '1');
INSERT INTO `order` VALUES ('6', 'sdasdsadasdas', 'lyy', '2021-03-23 19:23:48', '13219015380', '2', '48', '1');
-- ----------------------------
-- Table structure for order_item
-- ----------------------------
DROP TABLE IF EXISTS `order_item`;
CREATE TABLE `order_item` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`count` int(11) DEFAULT NULL,
`order_id` int(11) DEFAULT NULL,
`product_id` int(11) DEFAULT NULL,
`sub_total` double DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of order_item
-- ----------------------------
INSERT INTO `order_item` VALUES ('1', '1', '1', '10', '8888');
INSERT INTO `order_item` VALUES ('2', '2', '2', '9', '17998');
INSERT INTO `order_item` VALUES ('3', '2', '3', '11', '78');
INSERT INTO `order_item` VALUES ('4', '1', '3', '13', '5999');
INSERT INTO `order_item` VALUES ('5', '1', '4', '9', '8999');
INSERT INTO `order_item` VALUES ('6', '1', '5', '13', '5999');
INSERT INTO `order_item` VALUES ('7', '1', '6', '13', '48');