2 在线购物支付网站Shop
2.1 系统总体架构
2.2 系统流程图
2.3 页面展示
2.4 系统工程
2.4.1 工程结构截图
2.4.2 Shop-Parent工程
存放其他工程的工程依赖,是其他工程的负工程,方便对依赖的管理而建立。
maven依赖如下:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- eureka server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<!-- feign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<!-- 集成web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 集成lombok 框架 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- 集成redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 集成mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<!-- freemarker -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-- 阿里巴巴数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.14</version>
</dependency>
<!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.30</version>
</dependency>
<!-- springboot整合activemq -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<!-- 集成发送邮件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
</dependencies>
2.4.3 Shop-api工程
是SpringCloud远程调用的消费者和提供者的公共接口工程。包含Shop-api-item工程和Shop-api-member工程。
2.4.3.1 数据库设计
(1)用户表shop_users
CREATE TABLE `shop_user`(
`id` int(20) NOT NUll auto_increment COMMENT'主键(自增长)',
`username` VARCHAR(50) NOT NULL COMMENT'用户名',
`password` VARCHAR(32) NOT NULL COMMENT'密码,加密存储',
`phone` VARCHAR(20) DEFAULT NULL COMMENT'手机号',
`email` VARCHAR(50) DEFAULT NULL COMMENT'邮箱',
`openId` VARCHAR(100) DEFAULT NULL COMMENT'登录Id',
`created` TIMESTAMP not NULL DEFAULT CURRENT_TIMESTAMP COMMENT'自动插入,创建时间',
`updated` TIMESTAMP not null DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT'自动插入,修改时间',
PRIMARY KEY(`id`),
UNIQUE KEY `username` (`username`) USING BTREE,
UNIQUE KEY `phone` (`phone`) USING BTREE,
UNIQUE KEY `email` (`email`) USING BTREE
)ENGINE=INNODB COMMENT='用户表';
(2)商品信息表shop-item
CREATE TABLE `shop_item` (
`id` bigint(20) NOT NULL auto_increment COMMENT '商品id,同时也是商品编号',
`title` varchar(100) NOT NULL COMMENT '商品标题',
`sell_point` varchar(500) DEFAULT NULL COMMENT '商品卖点',
`price` bigint(20) NOT NULL COMMENT '商品价格,单位为:分',
`num` int(10) NOT NULL COMMENT '库存数量',
`barcode` varchar(30) DEFAULT NULL COMMENT '商品条形码',
`image` varchar(500) not NULL COMMENT '商品图片',
`desc_id` bigint(10) NOT NULL COMMENT '商品详情Id',
`cid` bigint(10) NOT NULL COMMENT '所属栏目',
`status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '商品状态,1-正常,2-下架,3-删除',
`created` TIMESTAMP not NULL DEFAULT CURRENT_TIMESTAMP COMMENT'自动插入,创建时间',
`updated` TIMESTAMP not null DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT'自动插入,修改时间',
PRIMARY KEY (`id`),
KEY `cid` (`cid`),
KEY `status` (`status`),
KEY `updated` (`updated`)
) ENGINE=InnoDB COMMENT='商品表';
(3)商品描述表shop_item_desc
CREATE TABLE `shop_item_desc` (
`id` bigint(20) NOT NULL auto_increment COMMENT '商品ID',
`itemdesc` text COMMENT '商品描述',
`created` TIMESTAMP not NULL DEFAULT CURRENT_TIMESTAMP COMMENT'自动插入,创建时间',
`updated` TIMESTAMP not null DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT'自动插入,修改时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='商品描述表';
(4)商品类目表shop_item_category
CREATE TABLE `shop_item_category` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '类目ID',
`name` varchar(50) not NULL COMMENT '类目名称',
`img` varchar(150) not NULL COMMENT '图片地址',
`status` int(1) DEFAULT '1' COMMENT '状态。可选值:1(正常),2(删除)',
`created` TIMESTAMP not NULL DEFAULT CURRENT_TIMESTAMP COMMENT'自动插入,创建时间',
`updated` TIMESTAMP not null DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT'自动插入,修改时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='商品类目';
2.4.3.2 实体类设计
完全和数据库字段一致。
2.4.4 Shop-common工程
将工程中常用的功能方法和类抽离出来。
2.4.5 Shop-EurekaServer工程
系统的Eureka注册中心工程。
配置文件:
server:
port: 8761
context-path: /
eureka:
instance:
hostname: localhost
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
2.4.6 Shop-Item工程
商品工程。
(1)额外添加的maven依赖
<!-- 集成mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
(2)配置文件
server:
port: 8764
context-path: /item
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
mybatis:
configuration:
# 开启驼峰uName自动映射到u_name
map-underscore-to-camel-case: true
spring:
application:
name: item
redis:
host: localhost
password: 123457
port: 6739
pool:
max-idle: 100
min-idle: 1
max-active: 1000
max-wait: -1
datasource:
name: test
url: jdbc:mysql://localhost:3306/shop
username: root
password: root
# 使用druid数据源
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
filters: stat
maxActive: 20
initialSize: 1
maxWait: 60000
minIdle: 1
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: select 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxOpenPreparedStatements: 20
2.4.7 Shop-Member工程
用户工程。
(1)额外添加的依赖
<!-- 集成mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
(2)配置文件
server:
port: 8762
context-path: /member
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
spring:
application:
name: member
redis:
host: localhost
password: 123457
port: 6379
pool:
max-idle: 100
min-idle: 1
max-active: 1000
max-wait: -11
datasource:
name: test
url: jdbc:mysql://localhost:3306/shop
username: root
password: root
# 使用druid数据源
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
filters: stat
maxActive: 20
initialSize: 1
maxWait: 60000
minIdle: 1
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: select 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxOpenPreparedStatements: 20
activemq:
broker-url: tcp://localhost:61616
user: admin
password: admin
message:
queue: message_queue
2.4.8 Shop-Message工程
发送注册邮件工程。
邮件的自定义报文:
{
"header":{
"interfaceType":"接口类型"
},
"content":{
"mail":" ",
"userName":" "
}
}
配置文件:
server:
port: 8763
context-path: /message
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
spring:
application:
name: message
activemq:
broker-url: tcp://localhost:61616
user: admin
password: admin
mail:
host: smtp.163.com
username: xiaoqianittest@163.com
password: DGTQZCESAMGOWPVT
enable: true
smtp:
auth: true
starttls:
enable: true
required: true
2.4.9 Shop-Moblie-Web工程
用户交互工程。
Redis中购物车信息格式:
key: userOpenId
value: { "cart":["itemId1", "itemId2", "itemId3"...] }
(1)额外添加依赖
<!-- https://mvnrepository.com/artifact/com.alipay.sdk/alipay-sdk-java -->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>3.7.110.ALL</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
(2)配置文件
server:
# port: 8763
port: 80
context-path: /Shop
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
spring:
freemarker:
suffix: .ftl
templateEncoding: UTF-8
templateLoaderPath: classpath:/templates/
mvc:
view:
prefix: /WEB-INF/
suffix: .jsp
application:
name: shop
redis:
host: localhost
password: 123457
port: 6379
pool:
max-idle: 100
min-idle: 1
max-active: 1000
max-wait: -1
2.5 系统介绍
本系统是在线购物支付网站,采用SpringCloud框架进行分布式系统的设计。整个系统中的角色包含注册中心,服务提供者和服务消费者。这里注册中心使用Spring Cloud Eureka,服务消费者是与用户交互的Web工程。服务提供者,共包含3个服务工程:用户服务、商品服务和邮件服务。服务的调用使用Spring Cloud Feign,RPC远程调用的数据通信是Restful风格,使用Json串。系统的数据库采用mySql,ORM框架使用Mybatis。
用户服务包含用户登录、注册和注册邮件通知功能。对应的数据库表包含用户名、邮件、密码等字段,其中用户名、邮件和手机号加了唯一索引。用户注册时,使用MD5算法对密码加密后再存入数据库。入数据库成功,则发送邮件报文到ActiveMQ的消息队列,等待邮件服务监听消息并发送邮件。用户登录在验证用户名和密码后,将随机生成的字符串作为loginToken令牌作为键,将用户的openId作为值存储到Redis中,目的是为了后面的购物车相关操作。
商品服务包含首页展示商品、查询商品详情功能。对应的数据库表分为商品信息表、商品详情表、商品类目表三个表。目的是为了解耦商品的信息,对商品表进行垂直拆分,表之间通过特定字段进行关联。首页展示商品时,将查询到的信息按照类目进行分类,最后封装到Map中传到前端页面。查询商品详情时,根据用户点击前端页面传回的商品Id值进行查询商品详情描述,并返回前端页面即可。
邮件服务包含监听邮件消息和发送邮件两部分。使用JMSListener监听队列消息,有消息时对消息格式进行校验,邮件格式为自定义报文,有特定的报文头。监听和校验完又叫消息后,对报文解析后发送邮件即可。
最后建立一个Web工程,作为服务消费,用来消费上述三个服务,同时提供和用户交互的页面和业务逻辑处理。除调用上述三个服务进行用户登录、注册、商品展示和查询功能外,该工程单独提供了购物车和支付功能。购物车功能以Redis服务器为核心进行存储信息。按照自定义的购物车信息格式,为两层键值对形式,第一层键为用户的openId,第二层键为常量字符串"cart",值为商品id的json数组。由此可以进行购物车的展示、删除商品、新增商品功能。最后支付功能对接支付宝的支付网关接口。使用支付宝开放平台的沙箱账号和工具以及Demo进行支付功能的整合。
系统的启动,只需启动Eureka、服务提供者和消费者工程即可。
2.6 一些开发笔记
都是我踩过的坑:
1、通过@requestBody可以将请求体中的JSON字符串绑定到相应的bean上,当然,也可以将其分别绑定到对应的字符串上。
2、在feignClient(服务提供者)端,要注意暴露接口的返回值为JSON,可以用@Controller + @ResponsedBody或者@RestController修饰。否则报错feign.FeignException: status 404 reading
3、在html中,href中,不加/包含context-path,如href="index",如果加/代表从域名开始拼接,href="/mobile/index"
4、从前端传过来的参数,若为空,是空字符串"",而不是null。
5、fastjson,注意怎么传list<类>,特别注意JSONARRAY里面的类型好像只能是Integer,注意怎么转化为需要的JAVA基本类型
6、Mybatis的Maven依赖,如果引用了,但是没有配置mysql会在启动报错
7、loadbalance error ...client: item,这类错误,可能需要重启一下工程即可
8、从json中提取实体类:ItemEntity item = itemJson.getObject(Constants.HTTP_RES_CODE_DATA, ItemEntity.class)
9、springcloud的api接口的参数需要用@RequestParam