在线商城Java项目(第一阶段)-服务端(环境和业务)
可在电脑上阅读,以获取最佳阅读效果,谢谢!
已支持在线查看PDF电子书版本
项目开始 20171018
结束时间 20171212 21:30
Git代码地址:https://gitee.com/jiangjiesheng/mmall/tree/v1.0
接口文档:https://gitee.com/jiangjiesheng/mmall/wikis/Home
点击在线阅读PDF电子书版本(无需下载)
目录
一、开发环境的安装预配置
1、Linux系统安装 CentOS 7 64位
2、软件源配置
3、jdk安装
4、Tomcat7 安装
5、Maven安装
6、vsftp搭建
7、Nginx安装
8、MySQL安装和配置
9、git安装
二、表结构
三、项目的初始化
四、用户模块的开发
五、后台管理模块
六、分类管理模块
七、商品管理
八、购物车模块
九、收货地址管理
十、支付模块开发-前期介绍和准备
十一、支付模块开发-业务层开发
十二、订单模块开发
十三、服务端项目自动化发布
---------------------------------------------相关服务启动-----------------------------------
1> 启动tomcat
/usr/xxxxx/tomcat7/apache-tomcat-7.0.73/bin/startup.sh
2> 启动防火墙
sudo service iptables restart
3> 启动ftp
/usr/sbin/vsftpd &
4> 启动nginx
#nginx: [error] open() "/usr/local/nginx/logs/nginx.pid" failed (2: No such file or directory)
---> /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
/usr/local/nginx/sbin/nginx -s reload # -s reload用于更新配置
5> 启动数据库
sudo service mysqld restart
一、开发环境的安装预配置
1、Linux系统安装 CentOS 7 64位
账户 root 123456,admin 123456
注意:关于Centos 7:
新装系统可能都需要先配置一下ip
1> ip 查看 ip addr (如果提示ip未知的话,需要修改ip配置)
http://www.cnblogs.com/dunitian/p/4974761.html
核心:cd /etc/sysconfig/network-scripts
打开 sudo vi ifcfg-eth0 (可能是eth1 或 ifcfg-ens33等,不一定相同)
设置BOOTPROTO=dhcp
ONBOOT=yes
保存后 service network restart
如果依然获取不到ip,shutdown -h 0 ,把网络适配器的NAT模式改为桥接模式
(不勾选复制物理网络连接状态)
安装完wget后好像就可以执行ifconfig
2> 安装wget: sudo yum -y install wget
2、软件源配置
阿里云源配置官网 http://mirrors.aliyun.com
Linux:centos6.8 64bit
http://mirrors.aliyun.com/centos/6.8/isos/x86_64/CentOS-6.8-x86_64-bin-DVD1.iso
阿里云软件源配置说明
centos:http://mirrors.aliyun.com/help/centos
3、jdk安装
如果安装centos6.8时默认安装了例如openjdk等,先执行rpm -qa | grep jdk(centos环境有效),然后卸载 sudo yum remove XXX。
下载 jdk
wget http://192.168.1.105:81/jdk-8u151-linux-x64-64bit.rpm
jdk包增加权限 sudo chmod 777 jdk-8u151-linux-x64.rpm
安装jdk : sudo rpm -ivh jdk-8u151-linux-x64.rpm
默认安装在/usr/java/下,然后设置环境变量,sudo vim /etc/profile , 追加
export JAVA_HOME=/usr/java/jdk1.8.0_151
export CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:
$JAVA_HOME/lib/tools.jar #(注意含有空格需要清除)
export PATH=$PATH:$JAVA_HOME/bin #注意有bin
保存后更新 source /etc/profile
4、Tomcat7 安装
1> 下载 wget http://192.168.1.105:81/apache-tomcat-7.0.73.tar.gz
2> 解压 tar -xvf apache-tomcat-7.0.73.tar.gz
安装路径位置 /usr/mylibs/tomcat7 --直接解压不能通过whereis 查询路径
3> 修改字符集
编辑 sudo vi conf/server.xml
搜索8080 ?8080
增加URIEncoding=“UTF-8”
4> 执行启动 /bin/startup.sh
或 cd bin后 ./startup.sh 执行启动 (需要重启防火墙)
访问测试 192.168.1.105:8080 -->打不开网页
继续配置步骤5>
5> 配置防火墙 (放在“7、Nginx安装”之后处理 !!)
安装iptable iptable-service
①关闭firewall
systemctl stop firewalld.service #关闭防火墙
systemctl disable firewalld.service #禁止firewall开机启动
②安装iptables防火墙
yum install iptables-services #安装iptables
vi /etc/sysconfig/iptables #编辑防火墙文件
(前期配置时最好完全关闭防火墙,后期直接下载配置文件 “iptables”)
添加80和3306端口
-A INPUT -m state –state NEW -m tcp -p tcp –dport 80 -j ACCEPT
-A INPUT -m state –state NEW -m tcp -p tcp –dport 3306 -j ACCEPT
systemctl restart iptables.service #重启防火墙使配置文件生效
systemctl enable iptables.service #设置iptables防火墙为开机启动项
③关闭SELINUX (此步骤未验证,暂时跳过)
vi /etc/selinux/config
#注释以下配置
SELINUX=enforcing
SELINUXTYPE=targeted
SELINUX=disabled
#增加以下配置
setenforce 0 #使配置立即生效
service iptables status #查看防火墙状态
具体配置见文件iptables.可以通过wget获取
重启防火墙 sudo service iptables restart
配置环境变量 export CATALINA_HOME=/xxxx/tomcat包文件夹路径
(应该不需要配置,跳过!!!)
5、Maven安装
1> 下载 wget http://learning.happymmall.com/maven/apache-maven-3.0.5-bin.tar.gz
2> 解压,添加环境变量
export MAVEN_HOME=/usr/mylibs/maven3/apache-maven-3.0.5
export PATH=$JAVA_HOME/bin:$MAVEN_HOME/bin:$PATH //注意有bin
保存后更新 source /etc/profile
3> 测试 mvn --version
4> maven常见命令
清除:mvn clean 编译:mvn compile 打包:mvn package
跳过单元测试:mvn clean package -Dmaven.test.skip=true
6、vsftp搭建
1> “very secure FTP daemon” --完全免费、开源
2> 安装
rpm -qa | grep vsftpd 检查是否安装
yum -y install vsftpd
cd / 进录根目录
mkdir ftpfile
cd ftpfile
sudo useradd ftpuser -d /ftpfile/ -s /sbin/nologin 创建虚拟用户(无登录权限)
提示主目录已存在....文件已存在-->忽略即可
(查看用户 cat /etc/passwd | grep ftpuser)
(删除用户 userdel ftpuser)
sudo chown -R ftpuser.ftpuser /ftpfile/ 改变拥有者和群组
检查权限
cd..
ll | grep ftp
设置755权限
sudo chmod 755 ftpfile/
设置密码
sudo passwd ftpuser
user123123(最新密码)
去ftpfile文件下创建index.html 并写入this is a ftpfile
3>默认ftp服务器
whereis vsftpd
让ftp服务器指向ftpfile文件夹并设置用户
sudo vi /etc/vsftpd/vsftpd.conf
搜索 ?banner
启动并修改成功登陆欢迎语
并在下一行追加
local_root=/ftpfile
anon_root=/ftpfile (可以忽略)
use_localtime=yes
搜索 ?chroot_list
启用
chroot_local_user=YES #关键 不启用时无法登陆
chroot_list_enable=YES
chroot_list_file=/etc/vsftpd/chroot_list
(如果使用/ 搜索,先按ESC,然后直接按/ )
搜索 /anon
关闭匿名访问 anonymous_enable=NO
搜索 /tcp
在一行增加(为了配合设置严格的防火墙)
pasv_min_port=61001
pasv_max_port=62000
并在iptables 添加端口限制
重启防火墙 sudo service iptables restart
保存关闭前复制出 /etc/vsftpd/chroot_list 路径
进入/etc/vsftpd/,并创建chroot_list文件,填入ftpuser
sudo vi /etc/selinux/config 修改SELINUX=disabled
sudo setsebool -P ftp_home_dir=1
sudo setsebool -P tftp_home_dir=1(好像需要执行这一条)
reboot 重启
启动ftp服务器 /usr/sbin/vsftpd &
重启ftp服务器 service vsftpd restart
1、若出现读取conf配置500错误
ll /etc/vsftpd/vsftpd.conf
该文件所属root用户,所以需要切换为root用户并重新执行启动ftp服务器
2、如果用户登录出现331,检查配置都是正确时,这里的 vi /etc/vsftpd/vsftpd.conf
好像不能有中文注释,去掉后重启服务
查看是否启动 pgrep vsftpd
关闭ftp服务器 pkill vsftpd
//更多配置见《Web-vsftpd-ftp服务器配置说明-CentOS-Linux》
《Web-vsftpd配置文件详解详解-ftp服务器-CentOS-Linux》
7、Nginx安装
Nginx(来自俄罗斯)是一款轻量级的Web服务器(可直接运行PHP),
也是一款反向代理服务器 (请求转发)
作用:
1>Nginx可运行Rails和PHP程序
2>作为HTTP反向代理服务器
3>作为负载均衡服务器
4>作为邮件代理服务器
5>帮助前端实现动静分离
特点:
高稳定、高性能、模块化结构、支持热部署、
资源占用少、功能丰富
安装步骤:
0> 直接执行 nginx安装依赖命令
1> 安装gcc
yum install gcc
gcc -v 查看版本,查看系统是否已安装
--可能是 yum install gcc-C++
2> 安装pcre
yum install pcre-devel
3> 安装zlib
yum install zlib zlib-devel
4> 安装openssl (如果需要支持ssl)
yum install openssl openss-devel
以上综合命令
nginx安装依赖命令
yum -y install gcc zlib zlib-devel pcre-devel openssl openssl-devel
5> 下载源码包,选择稳定版本,解压安装
wget http://192.168.1.105:81/linux-nginx-1.10.2.tar.gz
1> 解压后进入nginx目录 执行 ./configure
a> 也可在指定安装目录,增加参数 --prefix=/usr/nginx
b> 若不指定路径,可通过whereis nginx 进行查询
c> 默认安装在/usr/local/nginx
2> 执行make
3> 执行make install
Nginx常用命令
查看安装路径
whereis nginx
测试配置文件是否正确
安装路径下的 /nginx/sbin/nginx -t
启动命令
安装路径下的/nginx/sbin/nginx
或者进入/sbin目录 执行 sudo ./nginx
执行查看进程命令然后访问80端口验证是否成功
停止命令
安装路径下的 /nginx/sbin/nginx -s stop
或者是 nginx -s quit
重启命令
安装路径下的 /nginx/sbin/nginx -s reload
查看进程命令
ps -ef | grep nginx
或
ps aux | grep nginx
平滑重启
kill -HUP {Nginx主进程号(即查看进程命令查到的PID)}
--假如有新的配置文件,
--新的配置会在给已经连接的用户返回数据后生效
--假如新的配置文件有错误,nginx会继续使用旧的配置文件
增加防火墙访问权限
1> sudo vim /etc/sysconfig/iptables
2> -A INPUT -p tcp -m state --state New -m tcp --dport 80 -j ACCEPT
3> 保存并重启防火墙 sudo service iptables restart
Nginx虚拟域名配置及测试验证
本地测试环境注意配置host
--Linux sudo vi /etc/hosts
追加 127.0.0.1 mm.jiangjiesheng.cn
--Window
C:\Windows\System32\drivers\etc
主域名 全部定为 mm.jiangjiesheng.cn
配置步骤
1> 在/usr/local/nginx/conf/ 目录中新建vhost文件夹
即: /usr/local/nginx/conf/vhost
2>编辑 sudo vi /usr/local/nginx/conf/nginx.conf
在 #another virtual host using mix ...
增加 include vhost/*.conf; --加分号
保存退出
3> 本地测试添加虚拟域名测试
sudo vi /etc/hosts
192.168.134.134 mm.jiangjiesheng.cn
192.168.134.134 image.mm.jiangjiesheng.cn
192.168.134.134 s.mm.jiangjiesheng.cn --前端js css
//已将192.168.134.134 改成127.0.0.1进行测试
3> 创建域名转发配置
cd vhost
(whereis nginx --安装目录下,即 /usr/local/nginx/conf/vhost )
sudo vi mm.gestruectrl.com.conf
server {
default_type 'text/html';
charset utf-8;
listen 80;
autoindex on;
server_name mm.jiangjiesheng.cn;
access_log /usr/local/nginx/logs/access.log combined;
index index.html index.htm index.jsp index.php;
#error_page 404 /404.html;
if ( $query_string ~* ".*[\;'\<\>].*" ){
return 404;
}
location ~ /(mmall_fe|mmall_admin_fe)/dist/view/* {
deny all;
}
location / {
proxy_pass http://127.0.0.1:8080; #转发到tomcat服务器
add_header Access-Control-Allow-Origin *;
}
}
保存
whereis nginx
cd 复制如上安装目录
sbin/nginx -s reload 一定要加 -s reload
访问 mm.jiangjiesheng.cn 验证配置是否成功
保证tomcat 已启动
虚拟机中运行的系统好像不太好在window中测试域名转发功能!!!
通过wget mm.jiangjiesheng.cn 下载首页
cat index.html,从源码上检查是不是tomcat的首页
---> 此次验证配置成功
继续创建转发配置
sudo vi image.mm.jiangjiesheng.cn.conf 一定要加 .conf
server {
listen 80;
autoindex off;
server_name image.mm.jiangjiesheng.cn;
access_log /usr/local/nginx/logs/access.log combined;
index index.html index.htm index.jsp index.php;
#error_page 404 /404.html;
if ( $query_string ~* ".*[\;'\<\>].*" ){
return 404;
}
location ~ /(mmall_fe|mmall_admin_fe)/dist/view/* {
deny all;
}
location / {
root /ftpfile/; #指向路径
add_header Access-Control-Allow-Origin *;
}
}
保存
cd ..
cd ..
cd sbin/
sudo ./nginx -s reload 一定要加 -s reload
或者直接 /usr/local/nginx/sbin/nginx -s reload 一定要加 -s reload
测试
wget image.mm.jiangjiesheng.cn/index.html
cat index.html
This is a ftp file
---> 此次验证配置成功
//TODO 办公电脑从这里开始
继续创建转发配置
sudo vi s.mm.jiangjiesheng.cn.conf 一定要加 .conf
server {
listen 80;
autoindex off; #注意这里设置关闭,禁止直接列出文件列表
server_name s.mm.jiangjiesheng.cn;
access_log /usr/local/nginx/logs/access.log combined;
index index.html index.htm index.jsp index.php;
if ( $query_string ~* ".*[\;'\<\>].*" ){
return 404;
}
location ~ /(mmall_fe|mmall_admin_fe)/dist/view/* {
deny all;
}
location / {
root /product/front/;
add_header Access-Control-Allow-Origin *;
}
}
创建 /product/front/ 文件夹
继续重新加载配置验证
---> 此次验证配置成功
4> 启动(重启)验证
启动: ${nginx}/sbin/nginx
重启: ${nginx}/sbin/nginx -restart
--${nginx}默认是 /usr/local/nginx
5> 访问验证(如果部署在虚拟机中,注意使用wget测试)
mm.jiangjiesheng.cn
image.mm.jiangjiesheng.cn
s.mm.jiangjiesheng.cn
8、MySQL安装和配置
账户root root,admin admin
用户配置、权限配置、新建database
1 安装
具体安装过程见
《数据库-通过yum在CentOS7 64位下安装MySQL5.7.20的过程记录》
线上地址://tech.jiangjiesheng.cn/java/138.html
务必使用 《数据库-通过yum在CentOS7 64位下安装MySQL5.7.20的过程记录》
中的安装过程安装,并且把默认版本5.6改成5.7,出错时直接执行步骤8.
rpm -qa | grep mysql-server 确定是否已安装mysql-server
//CentOS 7+ 提示没有可用软件包 mysql-server。错误:无须任何处理
wget http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm
rpm -ivh mysql-community-release-el7-5.noarch.rpm
ls -1 /etc/yum.repos.d/mysql-community*
yum -y install mysql-server
默认配置文件在/etc/my.cnf
2 字符集配置
vim /etc/my.cnf
在 [mysqld]节点上添加
default-character-set=utf8
#在 CentOS 7 上启动会有错误(好像又是需要在7以上使用上面的)
character-set-server=utf8
3 自启动配置
1> 执行sudo chkconfig mysqld on
2> 执行sudo chkconfig --list mysqld (新版无效)
(如果2-5位为on表示成功 CentOS7 执行无效)
4 防火墙配置
1> sudo vi /etc/sysconfig/iptables
2> -A INPUT -p tcp -m tcp --dport 3306 -j ACCEPT
3> 保存
4> 重启防火墙 sudo service iptables restart
5 数据库初始化设置和访问权限配置
1> 查看目前mysql的用户(可能需要先自行步骤2>)
select user,host,password from mysql.user;
#Password 改成 authentication_string (新版)
---即 select user,host,authentication_string from mysql.user;
2> 修改root密码
set password for root@localhost=password('newpassword'); #非1旁边的引号
set password for root@127.0.0.1=password('newpassword');
3> 删除匿名用户
查看是否有匿名用户
select user,host from mysql,user;
删除匿名用户
delete from mysql.user where user='';
刷新使生效(关键)
flush privileges;
4> 插入mysql新用户(新版不支持直接插入用户,通过步骤 5>和 6>完成)
insert into mysql.user(Host,User,Password)
values("localhost","yourusername",password("yourpassword"));
Password 改成 authentication_string (新版)
5.7版本添加新用户
GRANT USAGE ON *.* TO 'root'@'127.0.0.1' IDENTIFIED BY 'yourpassword'
WITH GRANT OPTION;
刷新使生效(关键)
flush privileges;
5> 创建database
CREATE DATABASE `mmall` DEFAULT CHARACTER SET utf8 COLLATE
utf8_general_ci; #这里又是1旁边的引号
6> 本地用于赋予所有权限
grant all privileges on mmall.* to yourusername@localhost identified by
'yourpassword';
---即 grant all privileges on mmall.* to admin@localhost identified by 'admin';
刷新使生效(关键)
flush privileges;
7> 给账号开通外网所有权限
grant all privileges on mmall.* to yourusername@'%' identified by 'yourpassword'
---即 grant all privileges on mmall.* to admin@'%' identified by 'admin';
也可根据实际需要设置权限(指定命令、表、ip)
grant select,insert,update on mmall.* to yourusername@'192.11.11.11'
identified by 'yourpassword'
刷新使生效(关键)
flush privileges;
特别注意:
阿里云服务器开通时可能默认开通了安全组(阿里云控制台中设置),安全组
中需要设置对外网开通指定端口访问
8> 使用navicat工具连接测试(默认端口3306)
6 常用命令
1> 启动 sudo service mysqld start centOS7: /bin/systemctl start mysqld.service
-- sudo service mysqld restart (centos最新)
2> 关闭 sudo service mysqld stop
3> 重启 sudo service mysqld restart (使用这个来启动,避免错误)
4> 登录 mysql -uusername -h xxxhost -P 3306 -ppassword
其他相关命名见《数据库-MySQL 数据基本命令及安装配置方法》
7 其他介绍
数据库用户身份
dql -- select
dml -- insert update delete
ddl -- create table、create view
dcl -- grant
9、git安装
1> 下载 wget https://github.com/git/git/archive/v2.8.0.tar.gz
2> 安装依赖
sudo yum -y install zlib-devel openssl-devel cpio expat-devel gettext-devel curl-devel
perl-ExtUtils-CBuilder perl-ExtUtils-MakeMaker (先复制出来去掉换行符)
//TODO 安装?
解压v2.8.0.tar.gz,进入解压目录,
编译 sudo make prefix=/usr/local all
安装 sudo make prefix=/usr/local install
3> git基础配置(Windows在Git Bush中操作(命令相同) 桌面空白处右击)
a> 配置用户名(添加时会引用)
git config --global user.name "jiangjiesheng"
b> 配置邮箱(添加时会引用)
git config --global user.email "dev@jiangjiesheng.cn"
c> 其他配置
git config --global merge.tool "kdiff3"
(已安装KDiff3时可执行)
git config --global core.autocrlf false
(让git忽略Windows和Unix换行符转换)
d> 编码配置
git config --global gui.encoding utf-8
(避免git gui中的中文乱码)
git config --global core.quotepath off
(避免git status显示的中文文件名乱码)
Windows还需要配置
# git config --global core.ignorecase false
e> git ssh key pair配置
ssh-keygen -t rsa -C 'dev@jiangjiesheng.cn'
一直回车,不输入密码,生成ssh key pair
ssh-add ~/.ssh/id_rsa
cat ~/.ssh/id_rsa.pub
注:ssh-add ~/.ssh/id_rsa可能会出现Could not open a connection to your
authenticaciton agent,解决:
先执行 eval `ssh-agent` (1旁边的引号)
ssh-add ~/.ssh/id_rsa
ssh-add -l
复制公钥内容,到oschina的gitlab中,在右上角-->个人资料菜单-->修改资料
-->SSH公钥配置-->粘贴保存。
f> git验证
git --version命令
g> git常用命令
切换分支 git checkout 分支名
拉取 git pull
提交 git push
配置好git后备份系统 选pc版
二、表结构
1> 唯一索引 保证数据的唯一性
UNIQUE KEY `order_no_index` (`order_no`) USING BTREE
2> 单索引和组合索引,使查询更加快捷
KEY `order_no_index` (`order_no`) USING BTREE,
KEY `order_no_user_id_index` (`user_id`,`order_no`) USING BTREE
3> 时间戳(用于方便查业务问题)
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
//类型选择 datetime,不要使用date,因为要看具体的时间点
三、项目的初始化
1> 数据库初始化
2> IDEA 15
3> maven创建web项目并验证
File --> New --> Project --> Maven --> 勾选Create from archetype --> 选择 org.apache.maven.archetype.maven-archetype-webapp -->GroupId 填com.jianjiesheng, Artfacitid 填mmall --> next --> Project name 填mmall 并选择路径 --> Finish --> 自动创建maven项目
a> 在main文件夹下新建java文件夹,并右击java --> Mark Directory As --> Sources Root
在main文件夹下新建test文件夹,在test文件夹下创建java文件夹,并右击java --> Mark
Directory As -->Test Sources Root
b> 运行
Navigate --> Tool Windows --> Maven Projects --> Liftcycle --> 点击install生成war包
-->Run --> Edit Configurations --> Tomcat Server --> 配置tomcat路径 -->
Deployment选择Artifact--选择war包(或者external source 选择项目Target文件下的
xxx.war包)
//TODO 这里后期不删除 问题1
办公电脑还要继续安装windows下的git
安装好git后直接从git上克隆下来 然后切换到分支v1.0
# git remote add origin git@gitee.com:jiangjiesheng/mmall.git
使用克隆哪去代码
git checkout v1.0
办公电脑提交后 ,pc怎么更新?尝试借助idea 的Git工具
4> Git初始化
由于是在windows环境下开发,所有还要安装windows版git,参照步骤二,第9条
操作
注:IEDA直接执行git相关指令步骤二,第9条,3> 中的步骤a b c d
否则git pull 时提示
The authenticity of host 'gitee.com (120.55.226.24)' can't be established.
ECDSA key fingerprint is
SHA256:FQGC9Kn/eye1W8icdBgrQp+KkGYoFgbVr17bmjey0Wc.
1> 首先进入getee --> 右上角 --> +号 --> 新建项目--> 添加项目名 --> 语言选Java -->
开源许可证选择Apache V2 License --> 是否公开改为私有 --> 其他默认 --> 创建
2> 回到IEDA --> 左下角窗口 --> Terminal --> touch README.md -->
打开并输入mmall保存 -->
(注意windows下的Terminal不支持Linux指令:使用Git Bash(支持TAB,完全同Linux
用法):
--> cd /d/
--> cd workspace/idea/mmall
--> pwd
)
touch .gitignore --> 输入
*.class
#package file
*.war
*.ear
#kdiff3 ignore
*.orig
#maven ignore
target/
#eclipse ignore
.settings/
.project
.classpath
#idea ignore
.idea/
/idea/
*.ipr
*.iml
*.iws
#temp file
*.log
*.cache
*.diff
*.patch
*.tmp
# system ignore
.DS_Store
Thumbs.db
-->保存 --> git init --> git status --> git add . --> git status -->
git comit -am 'first commit init project' --> 此时保存到本地仓库 -->
连接远程仓库 (先去gitee-“克隆/下载”,复制出ssh地址)-->
git remote add origin git@gitee.com:jiangjiesheng/mmall.git -->
查看分支 --> git branch --> 准备提交 --> 先拉取 --> git pull --> 开始提交 -->
git push -u -f origin master (加-f 第一次强制覆盖远程仓库)--> 去getee刷新 -->
查看本地分支 --> git branch (结果为 * master)--> 查看远程分支 -->
git branch -r (结果为 origin/master) --> 在origin/master的基础上创建v1.0分支 -->
git checkout -b v1.0 origin/master --> 检查当前分支 --> git branch -->
将当前分支推送到远程 --> git push origin HEAD -u --> 去getee刷新 -->
分支中出现v1.0
另一台电脑拉取:
在一个项目目录下右击打开Git Bash,执行克隆命令,
注意会自动创建项目工程文件夹,所以不需要自己先创建工程文件夹
git clone git@gitee.com:jiangjiesheng/mmall.git
然后用IDE工具打开项目(open)
git status
提示在主分支上on branch master
git checkout v1.0 切换分支(本地没有分支会创建)
更新远程到本地
git pull
//分支开发 主干发布 (非必须)
其他git相关指令
git 本地仓库和远程仓库及本地分支和远程分支
http://www.cnblogs.com/ShaYeBlog/p/5576610.html
GIT - 基本概念(分支, 差异, 合并)
http://blog.csdn.net/seaee/article/details/51568261
Git 忽略一些文件不加入版本控制
http://www.jianshu.com/p/1a0e282026a5
5> Maven的pom文件配置
粘贴pom文本,执行Maven Project面板下的package,开始自动下载包
mybatis-generator-maven-plugin 1.3.2 不能下载
修改pom文件右上角不出现同步提示:
看左下角英文提示,点击,弹出Event Log 面板 这里有提示更新选择 -->
选择 Enable Auto-Import
或者右击pom.xml --> Maven --> Reimport
另外配置File > Setting > 搜索Maven > Maven home directory > 选择自己手动安装的
> User settings file 勾选Override (已设置阿里云的源)
某个库的相关pom信息 搜索 http://search.maven.org/
6> 项目结构初始化
a> 在java文件夹下创建包
com.mmall.controller
com.mmall.dao
com.mmall.service
com.mmall.util
com.mmall.vo (value object 或者view object 最终用于返回的)
复杂项目还可以添加bo(business object)--这里暂时不添加
com.mmall.pojo (简单的数据库对象)
注:pojo > vo > controller >前端展示
也可 pojo >bo > vo > controller >前端展示
com.mmall.common(常量、公共类)
7> Mybatis三剑客之mybatis-generator配置--由数据库生成dao?
根据数据库自动生成pojo、dao和对应的xml文件,pojo的字段和db的字段一一对应,dao层是接口和接口实现层,供service调用。xml是dao层接口的实现,即为sql语句。
1> 首先使用mybatis-generator这些文件
安装mybatis-generator(pom.xml中配置)
复制generatorConfig.xml到resource
http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd报红,
鼠标放上去,按提示Fetch external resource,即可
按照generatorConfig.xml中的配置,在resource文件夹同级目录下创建
datasource.properties,并添加数据库连接信息 db.driverLocation、
db.driverClassName、db.url db.username、db.password
特别注意:
db.driverLocation= D:/workspace/idea/mmall/src/main/webapp/lib/mysql-connector-java-5.1.6-bin.jar
# ./src/main/resources/webapp/lib/mysql-connector-java-5.1.6-bin.jar
#这是参考generatorConfig.xml的写法 但是实测无效
#测试要使用绝对路径 到时在linux中要换成pwd的路径
注:重新使用admin用户插入数据库会失败,要先去创建数据库
CREATE DATABASE `mmall` DEFAULT CHARACTER SET utf8 COLLATE
utf8_general_ci;
然后最好走一下赋予执行权限和外网访问权限的语句
然后在Navicat中刷新后,选中mmall后执行sql,一定要先选中
2> 使用这些配置文件生成mapper中的xml和dao层
在Maven Project面板中 > plugins > mybatis generator > 双击
(整个流程:先手动写好sql在数据库中执行,或者在直接在navicat创建表,
然后再通过mybatis-generator自动生成mapper中的xml和dao层)
如果是提示:
mybatis-generator-maven-plugin:1.3.2:generate failed:
Cannot resolve classpath entry: ******/mysql-connector-java-5.1.6.jar
按步骤1> 中的特别注意 处理
思考:
Hibernate 由dao生成数据库?
mybatis 由数据库生成dao?
执行成功后,com.mmall.pojo、com.mmall.dao、com.mmall.pojo、
resources\mappers\ 都生成相应资源
提交到gitee,注意IEAD开发工具上有Git插件,但是别使用,
使用Terminal 或者 Git Bash (先切换到mmall文件夹下)提交
git add .
git commit -am "20171029"
git brance ---> v1.0 如果不是,git checkout v1.0
git push origin HEAD -u
gitee 上刷新,要注意切换到v1.0的分支后查看
修改mappers下xml的语句,create_time 和 update_time 的values 改成now(),
注意insert 中 create_time 和 update_time 都改成now(), update语句中create_time默认,update_time改成now().
提交到gitee
8> Mybatis三剑客之mybatis-plugin安装--mappers-xml与dao关联
mybatis-plugin安装后在dao层和mappers文件打开后的左侧显示绿色箭头,
dao层方法与mappers层方法关联起来。
安装:
File > Settings > Plugins > Browse Repositories > 搜索 mybatis plugin 无结果
后期重新研究安装http://www.cnblogs.com/lyh421/p/7098898.html 版本 2.64
另个版本:idea版本15.0.2
下载mybatis_plus_2.62_5014.zip,File > Settings > Plugins > Install plugin from disk
9> Mybatis三剑客之mybatis-pagehelper安装--分页插件
开源 https://github.com/pagehelper/Mybatis-PageHelper
安装mybatis-pagehelper(pom.xml中配置)
10>
5个官方示例项目
http://projects.spring.io/spring-framework/
https://github.com/spring-projects/spring-mvc-showcase(spring配置demo)
https://github.com/spring-projects/spring-petclinic(spring配置demo)
https://github.com/spring-projects/greenhouse
https://github.com/spring-projects/spring-boot
11> Spring、SpringMVC配置
resources/applicationContext.xml
resources/applicationContext-datasource.xml
resources/datasource.properties
resources/logback.xml
resources/mmall.properties (ftp连接)
WEB-INF/dispatcher-servlet.xml
12> IDEA设置
Settings > 搜索compiler > 勾选Make project automatically
Settings > 搜索inspections > Spring > Spring Core > Code > Autowiring for Bean Class > 把Error改成Warining
提交代码
git status
git add .
git commit -am "create config files"
git push
13 接口调试和保存使用postman
FE助手(浏览器插件 > 用于优化显示json)QQ浏览器下免安装,浏览器使用极速模式
restlet_client (浏览器插件 > 用于测试接口并保存接口)
四、用户模块的开发
1> 功能:登录 用户名验证 注册 忘记密码
提交问题答案 重置密码 获取用户信息
更新用户信息 退出登录
主要技术:横向越权、纵向越权安全漏洞
MD5明文加密和salt值
Guava缓存的使用
高复用服务响应对象的设计思想及抽象封装(ServerReponse.java)
Mybatis-plugin使用技巧(前面章节已经学过)
session使用
相关解释:
横向越权:攻击者尝试访问与他拥有相同权限的用户的资源
(插入订单号能查其他用户的订单信息)
纵向越权:低级别攻击者尝试访问高级别用户的资源
相关接口
https://gitee.com/jiangjiesheng/mmall/wikis/Home
2> 代码
A> 首先登录的接口
a> 在controller包下新建portal包用于展示前端业务,并继续新建UserController,
给整个类添加注解 @Controller @RequestMapping("/user/")
并新建login方法
@RequestMapping(value = "login.do",method =RequestMethod.POST)
@ResponseBody
public Object login(String username, String password, HttpSession session) {
//service --> mybatis --> dao
return null;
}
b> 在service包下新建IUserService接口,并添加
ServerResponse login(String username, String password);
继续在service包下新建impl包,并UserServiceImpl implements IUserService。
c> 在common包下新增ServerResponse类和ResponseCode类,
并将Object 缓存ServerResponse
d> 在dao层的UserMapper 接口中,新增
//手动新增 以上是mybatis-generator 自动生成的
int checkUsername(String username);
//多个参数要使用Param注解
User selectLogin(@Param("username") String username,
@Param("password") String password);
d> 在UserMapper.xml中新增sql
e> 回到UserServiceImpl的实现类,完成login方法。
注意要给UserServiceImpl添加Service("iUserService") ,参数名称的原则是接口类名的首字母小写。
f> 在controller中注入iUserService 并完成调用,正常登陆用于接入到session
//注意在controller的类名上已经添加
@Controller
@RequestMapping("/user/")
-----------------------------------------------------------------------------------------
@RequestMapping(value = "login.do", method = RequestMethod.POST)
@ResponseBody
public ServerResponse login(String username, String password, HttpSession session) {
//service --> mybatis --> dao
ServerResponse response = iUserService.login(username, password);
if (response.isSuccess()) {
session.setAttribute(Const.CURRENT_USER, response.getData());
//Const.CURRENT_USER 为自定义产量类,后期应该和cookie结合,
//有cookie时也给登录并写入到session,这一过程都统一在拦截器中处理
}
return response;
}
B> 继续完成退出登录接口
@RequestMapping(value = "logout.do", method = RequestMethod.POST)
@ResponseBody
public ServerResponse logout(HttpSession session) {
session.removeAttribute(Const.CURRENT_USER);
return ServerResponse.createBySuccess();
}
C> 注册接口...
public ServerResponse register(User user) {
return null;
}
选中 iUserService.login ,Ctrl T,进入实现类,先写好实现类,IUserService接口, 完成contoller调用,过程反过来。
D> 校验用户名是否存在接口
ServerResponse checkValid(String str, String type)
E> 获取用户登录信息的接口
ServerResponse getUserInfo(HttpSession session)
//只从session中获取,没有则表示未登录
F> 获取忘记密码的问题的接口(未登录)
ServerResponse forgetGetQuestion(String username)
G> 校验忘记密码问题的回答接口(未登录)
public ServerResponse forgetCheckAnswer(String username,
String question, String answer)
利用Guava(LoadingCache) 编写本地缓存TokenCache
(回答问题并重置答案时两个接口需要用到token令牌进行检验,
防止横向越权,直接通过接口操作其他用户数据)
H> 重置密码的接口(未登录)
ServerResponse forgetResetPassword(String username,
String passwordNew, String forgetToken)
I> 登录状态的重置密码的接口
ServerResponse resetPassword(HttpSession session,
String passwordOld, String passwordNew)
J> 更新个人用户信息后的用户信息的接口
ServerResponse update_infomation(HttpSession session, User user)
//这里需要注意越权问题,还有username字段禁止更新的问题,
//userId 和username都要从session中获取,
//更新email时要判断新的email无其他用户正在使用。
K> 获取用户的详细信息的接口
ServerResponse get_information(HttpSession session) //注意去掉密码
五、后台管理模块
在controller包下新建backend包,并新建UserManageController
A> 后台登录的接口
public ServerResponse login(String username, String password,
HttpSession session)
B> 以后所有的接口验证并保存到postman中
测试环境的logback.xml中的日志路径可能需要修改
提交方式选择form-data
相关接口
https://gitee.com/jiangjiesheng/mmall/wikis/后台_用户接口?parent=接口
特别注意:
SpringMVC提交参数是为实体时User user,获取字段均为null的处理方案
1>加上注解@RequestBody User user
提交时使用json字符串(并指定application/json),jQuery提交时也要注意转成字符串
2> 使用x-www-form-urlencoded提交,使用form-data时字段为null,
与添不添加Headers(Content-Type application/x-www-form-urlencoded)似乎无关
相关接口:
http://localhost:8080/user/update_information.do
--------------第一阶段完成 2017-1110-1555-------------
六、分类管理模块
功能:后去节点、增加节点、修改名称、获取分类ID、递归子节点ID
目标:如何设计及封装无限层级的树状数据结构(DB设计:id parent_id)
递归算法的设计思想
如何处理复杂对象的排重
重写hashcode和equal方法
相关接口:https://gitee.com/jiangjiesheng/mmall/wikis/后台_品类接口?parent=接口
A> 增加分类接口
在backend包下创建CategoryManageController控制器
@Controller
@RequestMapping("/manage/category")
public class CategoryManageController {
public ServerResponse addCategory(HttpSession session,
String categoryName,
@RequestParam(value = "parentId", defaultValue = "0") int parentId) {
//注意添加可选时的默认值
}
}
创建 public interface ICategoryService
public class CategoryServiceImpl implements ICategoryService
并完成 public ServerResponse addCategory(String categoryName, Integer parentId)
的接口方法实现
B> 更新分类名称的接口
ServerResponse setCategoryName(HttpSession session, Integer categoryId,
String categoryName)
C> 查询子节点的分类信息,并且不递归,保持平级的接口
ServerResponse getChildrenParallelCategory(HttpSession session, @RequestParam(value = "categoryId", defaultValue = "0") Integer categoryId)
D> 查询当前节点的id和递归子节点的id的接口
ServerResponse getCategoryAndDeepChildrenCategory(HttpSession session, @RequestParam(value = "categoryId", defaultValue = "0") Integer categoryId)
使用Set排重
递归算法(这里没有用到尾递归)
重写Category实体equals 和 hashcode 方法使判断因子都是id
(可使用快捷键快速完成代码 Mac中快捷键可能是Command + Enter)
/**
* 重写equals 和 hashcode 使判断因子都是id
*/
@Override
public boolean equals(Object o) {
if(this ==o) return true;
if(o==null || getClass() !=o.getClass()) return true;
Category category = (Category) o;
return !(id != null ? !id.equals(category.id):category.id!=null);
}
@Override
public int hashCode() {
return id !=null?id.hashCode():0;
}
验证:在postman中完成接口测试
注意
接口参数加上 @RequestParam(value = "categoryId", defaultValue = "0") 时,
字段大小写是敏感的。这里的categoryId不能写成categoryid
SpringMVC Controller接收中文参数乱码
除了已有的配置外(https://www.cnblogs.com/alivn/p/4823405.html)
还需要配置Tomcat服务器
SpringMVC Controller接收的中文参数乱码
来自网络的解释:测试有效(https://www.cnblogs.com/esther-qing/p/6425590.html )
CharacterEncodingFilter只对POST请求有用,GET请求的需要对你运行的tomcat 目录conf/server.xml文件中
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
改为:
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" useBodyEncodingForURI="true"/>
这是tomcat的原因造成的,tomcat默认的编码是iso-8859-1。不是大家常用的utf-8。
换句话说,get请求是对资源的访问,资源我一般不会涉及中文路径(最好不要)。
不添加导致get中的中心参数读取错误
post 针对于数据的提交,所以如果是表单,最好用post请求。
另外jsp中的中文乱码(使用editplus查看是utf8,添加head编码无效,上述设置Tomcat无效)
在jsp中添加<%@ page language="java" contentType="text/html; charset=UTF-8" %>
可解决
七、商品管理
功能:(前台)产品搜索、动态排序列表、产品详情
(后台)商品列表、商品搜索、图片上传、富文本上传、商品详情、商品上下架
增加商品、更新商品
目标:FTP服务的对接、SpringMVC文件上传、流读取Properties配置文件
抽象POJO、BO、VO对象之间的转换关系及解决思路
joda-time快速入门(日期/时间库 在pom.xml中引入)
静态块、MyBatis-PageHelper高效准确地分页及动态排序
Mybatis对List遍历的实现方法
Mybatis对where语句动态拼接的版本演进
Pojo、BO、VO:
Controller --- VO-view object
↑↓
Service --- BO-business object
↑↓
Dao --- POJO-Plain Ordinary Java Object
POJO、VO:
Controller & Service --- VO-value object
↑↓
Dao --- POJO-Plain Ordinary Java Object
接口地址:
https://gitee.com/jiangjiesheng/mmall/wikis/后台_产品接口?parent=接口
https://gitee.com/jiangjiesheng/mmall/wikis/门户_产品接口?parent=接口
A> 增加或修改商品接口
ServerResponse productSave(HttpSession session, Product product)
B> 产品上下架接口
ServerResponse setSaleStatus(HttpSession session, Integer productId,Integer status)
C> 获取商品详情的接口
public ServerResponse getDetail(HttpSession session, Integer productId)
含有配置读取工具(PropertiesUtil.java)
静态块static{ }(仅会执行一次)优于 普通代码块{ } 优于 构造器代码块
日期时间转换工具 (DateTimeUtil.java)
D> 获取商品列表的接口
ServerResponse getList(HttpSession session, @RequestParam(value = "pageNum",
defaultValue = "1") int pageNum, @RequestParam(value = "pageSize",
defaultValue = "10") int pageSize)
含有MyBatis pagehelper 通用分页拦截器(AOP 面向切面,自动拦截,自动修改sql)
特别注意:pagehelper会在mapper的sql语句后自动添加limit,
所以mapper语句不能添加分号结束!
PageHelper.startPage(pageNum, pageSize);
List productList = productMapper.selectList();
List productDetailVoList = Lists.newArrayList();
for (Product productItem : productList) {
ProductDetailVo productDetailVo = assembleProductDetailVo(productItem);
productDetailVoList.add(productDetailVo);
}
//收尾
PageInfo PageResult = new PageInfo(productList);//后期还可以支持添加条件
PageResult.setList(productDetailVoList);这个构造器中没有set list集合
E> 后台商品搜索的接口
public ServerResponse productSearch(HttpSession session, String productName,
Integer productId, @RequestParam(value = "pageNum", defaultValue = "1") int
pageNum, @RequestParam(value = "pageSize", defaultValue = "10") int pageSize)
sql语句where中的判断
/*或者硬编码 where 1=1 保证拼接的sql不是错误的*/
AND name like #{productName}
AND id = #{productId}
F> 文件上传
①public ServerResponse upload(MultipartFile file, HttpServletRequest request)
②public Map richtextImgUpload(HttpSession session, @RequestParam(value =
"upload_file", required = false) MultipartFile file, HttpServletRequest request,
HttpServletResponse response)
包含SpringMVC上传文件配置
FTP上传文件(FTPUtil.java)
getServletContext.getRealPath()为null
http://blog.csdn.net/itguaicai/article/details/42583167
修改c测试保存的路径:D:/workspace/idea/mmall/target/mmall/WEB-INF/classes/upload
G> 前台的ProductController
前台获取商品详情的接口
public ServerResponse detail(Integer productId)
H> 用户搜索商品接口(返回list)
ServerResponse list(@RequestParam(value = "keyword", required = false)
String keyword, @RequestParam(value = "categoryId", required = false) Integer
categoryId,@RequestParam(value = "pageNum", defaultValue = "1") int pageNum,
@RequestParam(value = "pageSize", defaultValue = "10") int
pageSize,@RequestParam(value = "orderBy", defaultValue = "") String orderBy)
这里有mapper中遍历集合
<select id="selectByNameAndCategoryIds" parameterType="map" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List"/>
from mmall_product
where status = 1
<if test="productName!=null">
and name like #{productName}
</if>
<if test="productIdList!=null">
and category_id in
<foreach collection="productIdList" item="item" index="index" open="(" separator=","
close=")">
#{item}
</foreach>
</if>
</select>
前台和后台商品模块接口测试
https://gitee.com/jiangjiesheng/mmall/wikis/后台_产品接口?parent=接口
https://gitee.com/jiangjiesheng/mmall/wikis/门户_产品接口?parent=接口
八、购物车模块
功能:加入商品 更新商品数 查询商品数 移除商品 单选/取消 全选/取消 购物车列表
目标:购物车模块的设计思想
如何封装一个高复用购物车核心方法
解决浮点型在商业运算中丢失精度的问题
相关接口:https://gitee.com/jiangjiesheng/mmall/wikis/门户_购物车接口?parent=接口
A> 购物车中添加商品的接口
public ServerResponse add(HttpSession session, Integer count, Integer productId);
这里需要封装vo层(ValueObject or ViewObject)的CartProductVo层和
CartVo层(CartVo是CartProductVo 的集合)
计算精度的问题(BigDecimal)
在单元测试包下新建com.mmall.test
@Test
public void test1() {//单元测试中的返回值一定是void
System.out.println(0.05 + 0.01);//0.060000000000000005
System.out.println(1.0 - 0.42);//0.5800000000000001
System.out.println(4.015 * 100);//401.49999999999994
System.out.println(123.3 / 100);//1.2329999999999999
}
@Test
public void test2() {
BigDecimal b1 =new BigDecimal(0.05);
BigDecimal b2 =new BigDecimal(0.01);
System.out.println(b1.add(b2));
//0.06000000000000000298372437868010820238851010799407958984375
}
@Test
public void test3() {
BigDecimal b1 =new BigDecimal("0.05");
BigDecimal b2 =new BigDecimal("0.01");
System.out.println(b1.add(b2));// 0.06
}
float 和 double 只能用来做科学计算或工程计算
在商业计算中要使用BigDecimal的String构造器
进入BigDecimal类,Ctrl + O 查看所有的方法,
找到double的构造器(public BigDecimal(double val))这里的注释给出了说明
开始封装BigDecimal工具类 /util/BigDecimalUtil
要重点研究CartServiceImpl.getCartVoLimit()这个方法对于后台计算和对VO的处理
B> 更新购物车的接口(以下几个接口都会复用CartServiceImpl.getCartVoLimit()方法)
ServerResponse<CartVo> update(HttpSession session, Integer count, Integer productId)
C> 在购物车中删除接口
ServerResponse<CartVo> deleteProduct(HttpSession session, String productIds)
注意这里可能会删除多个商品,所以productId用逗号拼接成字符串。
使用Guava将productIds字符串转成List
List<String> productList = Splitter.on(",").splitToList(productIds);
if (CollectionUtils.isEmpty(productList)) {
return ServerResponse.createByErrorCodeMessage(ResponseCode.ILLEGAL_ARGUMENT.getCode(), ResponseCode.ILLEGAL_ARGUMENT.getDesc());
}
另外mapper中foreach遍历用法
<delete id="deleteByUserIdProductIds" parameterType="map">
DELETE from mmall_cart
where user_id = #{userId}
<if test="productIdList != null">
and product_id in
<foreach collection="productIdList" item="item" index="index"
open="(" separator="," close=")">
#{item}
</foreach>
</if>
</delete>
D> 查询购物车的接口
public ServerResponse<CartVo> list(HttpSession session) ;
E> 设置全选、全反选、单独选,单独反选接口
ServerResponse<CartVo> selectAll(HttpSession session)
public ServerResponse<CartVo> unSelectAll(HttpSession session)
public ServerResponse<CartVo> select(HttpSession session, Integer productId)
public ServerResponse<CartVo> unSelect(HttpSession session, Integer productId)
G> 获取购物车中商品的数量的接口
注意sum(字段)是对值的求和,而count是对行数row的统计
另外注意字段是空值的情况
select IFNULL(sum(quantity) ,0) as count from mmall_cart (编译器只提示NULLIF)
ServerResponse<Integer> getCartProductCount(HttpSession session)
购物车模块接口
https://gitee.com/jiangjiesheng/mmall/wikis/门户_购物车接口?parent=接口
九、收货地址管理
功能:添加地址、删除地址、更新地址、地址列表、地址分页、地址详情
目标:SpringMVC数据绑定中的对象绑定
MyBatis自动生成主键、配置和使用
巩固如何避免横向越权漏洞
相关接口:
https://gitee.com/jiangjiesheng/mmall/wikis/门户_收货地址接口?parent=接口
A> 增加地址的接口
使用MyBatis往MySQL数据库中插入一条记录后,返回该条记录的自增主键值:
useGeneratedKeys="true" keyProperty="id" ,这样就能getxxxId()获取,
否则insert之后只能返回成功insert的条数
public ServerResponse add(HttpSession session, Shipping shipping)
B> 删除地址的接口
注意横向越权:插入条件加入user_id
int deleteByShippingIdUserId(@Param("userId") Integer userId,
@Param("shippingId") Integer shippingId);
public ServerResponse add(HttpSession session, Integer shippingId)
C> 更新地址的接口
注意横向越权:
shipping对象的userid要使用session中的userid来set进来
并新增一个mapper方法,update条件加入user_id
注意update中的set user_id 要去掉。
parameterType="com.mmall.pojo.Shipping"
public ServerResponse update(HttpSession session, Shipping shipping)
D> 查询地址的详情接口
注意横向越权:
public ServerResponse select(HttpSession session, Integer shippingId)
E> 地址分页接口
public ServerResponse list(HttpSession session, @RequestParam(value =
"pageNum", defaultValue = "1") int pageNum, @RequestParam(value = "pageSize",
defaultValue = "10") int pageSize)
收货地址模块
https://gitee.com/jiangjiesheng/mmall/wikis/门户_收货地址接口?parent=接口
十、支付模块开发-前期介绍和准备
功能:支付宝对接 支付回调 查询支付状态
目标:熟悉支付宝对接的核心文档,调通支付宝支付功能官网demo
解析支付SDK对接源码
RSA1和RSA2验证签名及加解密
避免支付宝重复通知和数据校验
natapp外网穿透和tomcat remote debug
生成二维码,并持久化到图片服务器
相关接口:https://gitee.com/jiangjiesheng/mmall/wikis/门户_支付接口?parent=接口
重要的官网文档:
1> 沙箱登录:
https://openhome.alipay.com/platform/home.htm
2> 沙箱使用说明
https://docs.open.alipay.com/200/105310
3> 如何使用沙箱环境
https://docs.open.alipay.com/200/105311/
4> 当面付产品介绍
https://docs.alipay.com/mini/introduce/pay
5> 扫码支付接入指引
https://docs.open.alipay.com/194/106078
6> 当面付快速接入
https://docs.open.alipay.com/194/105170
7> 当面付接入必读
https://docs.open.alipay.com/194/105322
8> 当面付进阶功能
https://docs.open.alipay.com/194/105190
9> 当面付的异步通知-仅用于扫码支付
https://docs.open.alipay.com/194/103296
10> 当面付SDK&DEMO
https://docs.open.alipay.com/194/105201
11> 服务端SDK
https://docs.open.alipay.com/54/103419
12> 生成RSA密钥(下载工具)
https://docs.open.alipay.com/291/105971
13> 线上创建应用说明
https://docs.open.alipay.com/200/105310
支付宝扫码支付重要字段
关键入参:
out_trade_no 商户订单号,需要保证不重复
total_amount 订单金额
subject 订单标题
store_id 商户门店编号
timeout_express 交易超时时间
关键出参
qr_code 订单二维码图片地址
回调验证
签名、金额、订单号、订单状态、交易状态、商户id
回调具有幂等性并过滤掉重复的通知
一定要验证并确保可接受的通知是支付宝发出的
回调请求的返回(success)
支付宝扫码支付对接技巧
a>路由器设置开放本地到外网(不推荐)
b>外网远程debug:
1、保持远端代码版本和本地代码保持一致
2、及时关闭开放的debug端口(tomcat具体配置见百度,
并将端口开放到防火墙)
c>内网穿透
ngrok、natapp、花生壳
支付宝沙箱环境登录
https://sandbox.alipaydev.com/sms/receive.htm
沙箱应用
https://sandbox.alipaydev.com/user/accountDetails.htm(可下载Android版本demo)
沙箱账号(已注册自研开发者,含有商家和买家)
https://openhome.alipay.com/platform/appDaily.htm?tab=account
买家账号sfntqd8490@sandbox.com
登录密码111111
支付密码111111
商家账号tipxhp1149@sandbox.com
商户UID2088102174677656
登录密码111111
支付宝回调地址
http://mm.jiangjiesheng.cn/order/alipay_callback.do 已在mmall.properties中配置
(window上测试的话,可能要换一下了)
当面付demo和sdk
https://docs.open.alipay.com/54/104506/
https://docs.open.alipay.com/194/105201/
调通当面付官方demo注意事项
首先完成相关公钥、私钥、ppid等等信息,生成RSA密钥(需要下载工具
https://docs.open.alipay.com/291/105971)
Configs.init("zfbinfo.properties"); 读取zfbinfo.properties 失败,找不到文件
新建一个文件夹(不确定是包还是文件夹),例如resource,将放入zfbinfo.properties,
File-->Project Structure-->Project Settings-->Modules-->Sources-->选中resource,点
击"Resource"(带有饼形图标)即可
支付测试
运行Main类后,支付宝在返回的信息中含有qr_code字段,复制出来直接生成二维码,
使用沙箱环境中的支付宝应用并登陆买家账号扫码下单,支付成功后,可切换到商家支
付宝账号查看交易订单
继续尝试运行demo的web站点效果
配置tomcat时选择Deployment时无Artifacts,应该是demo在eclipse环境下创建的
处理:File-->Project Structure-->Project Settings-->Facets-->+号-->Web-->全中-->apply
-->Artifacts-->Web Application:Exploded-->From Modules-->选中-->apply
--->把WebRoot目录下的文件复制到Web(Web在上述操作后会自动生成)
--->重新配置tomcat发布的Deployment,选择Artifacts--->选中war-->(正式环境下应该需要
重新配置lib-->直接右击设置lib,或者File-->Project Structure-->Project Settings-->
Libraries-->点击右边的第一个+号选中lib,另外通过mudule-->Dependences-->+号-->jars
也行)-->重启tomcat-->打开web站点成功
打开Web首页,选择“当面付2.0 二维码支付”,输入测试数据并生成持久化二维码,沙箱扫
码并支付。并通过NATAPP远程调试支付宝回调(好像仅仅演示)
正式开始把支付集成到项目中
拷贝zfbinfo.properties和4个支付宝SDK
在WEB-INF下创建lib文件夹粘贴sdk,其依赖的jar包通过pom加载进来,然后将支付宝SDK的
jar添加到项目library引用中,并运行Main类测试,看看有没有问题
十一、支付模块开发-业务层开发
首先在controller/portal中创建OrderController
A> 支付宝预下单、生成当面付二维码接口
public ServerResponse pay(HttpSession session, Long orderNo, HttpServletRequest
request) //含有二维码生成后持久化到FTP图片服务器(qrimg专用文件夹)
B> 支付宝回调接口及支付宝SDK解析
public Object alipayCallback(HttpServletRequest request)
当面付异步通知-仅用于扫码支付 https://docs.open.alipay.com/194/103296
异步返回结果的验签:
(验证回调的正确性,是不是支付宝发的,并且要避免重复通知)
https://docs.open.alipay.com/194/103296
Ctrl Shift T --> Search AlipaySignature
Ctrl o ,继续输入rsaCheckV2 (打开重载的第一个)--> 追加使用StringBuffer,并发时线程安全(但是效率低)
支付宝demo默认的验证签名的rsaCheckContent中的类型是SHA1WithRSA
(java.security.Signature signature = java.security.Signature.getInstance(AlipayConstants.SIGN_ALGORITHMS); )
而不是RSA2
继续看rsaCheckV2重载的第二个方法 rsaCheckV2(Map params, String publicKey,String charset,String signType)
可以指定signType签名类型 最终调用的是SHA256WithRSA
注意 publicKey是支付宝公钥不是商家公钥,沙箱可以看到https://sandbox.alipaydev.com/user/accountDetails.htm
按照支付宝验签的要求,需要去掉sign和sign_type两个字段,sign字段支付宝在sdk中已经remove,但是sign_type没有去掉,其他的第一至第四步都已经在SDK中处理过
商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,并判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),
同时需要校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email),
上述有任何一个验证不通过,则表明本次通知是异常通知,务必忽略。在上述验证通过后商户必须根据支付宝不同类型的业务通知,正确的进行不同的业务处理,并且过滤重复的通知结果数据。
在支付宝的业务通知中,只有交易通知状态为TRADE_SUCCESS或TRADE_FINISHED时,支付宝才会认定为买家付款成功。
支付宝交易状态说明:
WAIT_BUYER_PAY 交易创建,等待买家付款
TRADE_CLOSED 未付款交易超时关闭,或支付完成后全额退款
TRADE_SUCCESS 交易支付成功
TRADE_FINISHED 交易结束,不可退款
C> 轮询查订单的支付状态的接口
public ServerResponse queryOrderPayStatus(HttpSession session, Long orderNo)
十二、订单模块开发
功能:
前台:创建订单 商品信息(为预下单准备) 订单列表 订单详情 取消订单
后台:订单列表 订单搜索 订单详情 订单发货
目标:
避免在业务逻辑中横向越权和纵向越权等安全漏洞
设计实用、安全、扩展性强大的常量、枚举类
订单号生成规格(集群时需要另外考虑)、订单号严谨性判断
POJO和VO之间的实际操练
MyBatis批量插入
相关接口:
https://gitee.com/jiangjiesheng/mmall/wikis/门户_订单接口?parent=接口
https://gitee.com/jiangjiesheng/mmall/wikis/后台_订单接口?parent=接口
前台:
前台接口都写在controller/portal中的OrderController里
A> 创建订单的接口
public ServerResponse create(HttpSession session, Integer shippingId)
B> 取消订单的接口
public ServerResponse cancel(HttpSession session, Long orderNo)
C> 获取购物车中产品的接口(购物车中十件选五件,用于展示这五件的详情)
public ServerResponse getOrderCartProduct(HttpSession session)
D> 订单详情的接口
public ServerResponse detail(HttpSession session, Long orderNo)
E> 个人中心查看个人订单的接口
public ServerResponse list(HttpSession session, @RequestParam(value =
"pageNum",defaultValue = "1") int pageNum, @RequestParam(value = "pageSize",
defaultValue ="10") int pageSize)
后台接口都写在controller/backend中的OrderManageController里
A> 后台查看订单列表的接口
public ServerResponse orderList(HttpSession session,
@RequestParam(value = "pageNum", defaultValue = "1") int pageNum,
@RequestParam(value = "pageSize", defaultValue = "10") int pageSize)
B> 后台查看订单详情的接口
public ServerResponse orderDetail(HttpSession session, Long orderNo)
C> 后台带分页搜索的接口
public ServerResponse orderSearch(HttpSession session, Long orderNo,
@RequestParam(value = "pageNum", defaultValue = "1") int pageNum,
@RequestParam(value = "pageSize", defaultValue = "10") int pageSize)
D> 后台发货的接口
public ServerResponse orderSendGoods(HttpSession session, Long orderNo)
十三、服务端项目自动化发布
下载自动化发布脚本,然后根据脚本内容创建git仓库文件夹
mkdir -p /developer/git-repository/
进入,并克隆gitee中的项目(注意选择SSH协议)git@gitee.com:jiangjiesheng/mmall.git
git clone git@gitee.com:jiangjiesheng/mmall.git
(如果提示没有权限,加sudo后提示git命令不存在,就把developer文件夹的所有者设置为当前用
户(一般是非root用户))
sudo chown -R xxxx /developer/
如果是设置给其他用户(xxxx后后一致):
sudo chown -R xxxx.xxxx /developer/
下载自动发布脚本deploy.sh,并修改git项目名(mmall),修改deploy.sh中的分支为v1.0,修改
tomcat安装的路径后保存,请增加执行权限 chmod 777 deploy.sh
PC虚拟机中的deploy.sh在/home/admin/mylibs 文件夹下...
// deploy.sh位置已经修改到了 /developer 文件夹下,并改名为 backend-deploy.sh
(chmod u+x g+x o+x a+x 777)
Logback日志说明:(相关配置在logback.xml中)
Linux下日志说明:
· 由于CentOS系统安装的tomcat在/usr/mylibs/tomcat7/apache-tomcat-7.0.73,其运行相关的日志在/usr/mylibs/tomcat7/apache-tomcat-7.0.73/logs下,
Windows下的日志说明:
log的日志最终记录在tomcat服务器所在盘的相应绝对路径下
windows测试时在C盘:
/developer/apache-tomcat-7.0.73/logs/mmall.log
结束时间2017-12-12 21:30
/**
* Description:
* Author:江节胜
* Email:dev@jiangjiesheng.cn
* Date: ${DATE}
*/