项目概述

此电商项目为本人学习项目,后端 使用nginx实现负载均衡转发请求到多台tomcat服务器,使用多台 redis服务器分布式 缓存用户登录信息。

项目已经部署到阿里云服务器,从阿里云linux服务器租用,到项目前后台代码的完善,前后花费了3个月左右的时间。

项目地址

本人已经部署该项目,租用的阿里云服务器的ip地址为:47.106.172.105,购买的域名地址为:www.xwld.site

商城地址为:http://www.xwld.site

大部分商品详情图片还没有上传,暂时只上传了一个商品用于演示。

地址:http://www.xwld.site/list.html?categoryId=100006

后端所用技术

  • Spring
  • SpringMVC
  • MyBatis
  • MySQL
  • Lombok:省去手动创建setter和getter方法
  • Mycat:数据库分库分表中间件
  • Redis:缓存
  • Jedis:Redis的Java Client
  • Nginx
  • Tomcat
  • Maven
  • 第三方接口
    • 支付宝沙箱测试接口,实现订单支付

前端所用技术

  • Html
  • Css
  • JavaScript
  • Node.js
  • Npm
  • Webpack
  • Charles

项目架构及功能模块图

linux项目运行的shell脚本

首先从码云中拉取项目对应的tag,然后进入项目目录,执行maven打包命令。

[root@izwz918nqae9soh0p70seuz bin]# cat mall_backend.sh
#!/bin/bash
# author xw
# create_date 2018年11月6日
"===========进入git项目mmall目录============="
cd /app/gitRepository/mmall_backend
echo "==================删除之前的tag====================="
rm -rf *
echo "==========git切换分之到mmall-v1.0==============="
git clone --branch back_release_$ git@gitee.com:xwmall/backend.git
echo "===========编译并跳过单元测试===================="
cd backend/mmallv4.
mvn clean package -Pprod -Dmaven.test.skip=true
echo "============删除旧的ROOT.war==================="
rm -rf /soft/tomcat1/webapps/ROOT.war
echo "======拷贝编译出来的war包到tomcat下-ROOT.war======="
cp /app/gitRepository/mmall_backend/backend/mmallv4./target/mmall.war /soft/tomcat1/webapps/ROOT.war echo "============删除tomcat下旧的ROOT文件夹============="
rm -rf /soft/tomcat1/webapps/ROOT echo "====================关闭tomcat====================="
#/soft/tomcat1/bin/shutdown.sh
pkill - java
echo "================sleep 10s========================="
for i in {..}
do
echo $i"s"
sleep 1s
done echo "====================启动tomcat====================="
/soft/tomcat1/bin/startup.sh

github与 码云

码云

此项目本人使用码云来存储项目

每发布一个版本创建一个tag标记,shell 中使用git命令获取相应的tag版本

github

github上面是目前是没什么项目,

由于github上面创建私有的项目需要收费,故而,一直使用码云来存储项目,等到后期项目再进一步完善,再迁移到github中开源。

github地址如下:https://github.com/weiqinshian/mall

项目完整购买流程展示

首页

商品列表页面

暂时只上传了一个商品。

地址:http://www.xwld.site/list.html?categoryId=100006

商品详情页面

地址:http://www.xwld.site/detail.html?productId=27

登录页面

地址:http://www.xwld.site/user-login.html?redirect=http%3A%2F%2Fwww.xwld.site%2Forder-detail.html%3ForderNo%3D1549504659738

测试账号:admin

密码:123456

购物车页面

订单确认页面

生成支付二维码页面

本人手机安装了沙箱测试版支付宝,使用沙箱测试版支付宝扫码支付。

手机扫码支付成功之后

查看订单详情

redis 分布式缓存session

项目中集成redis客户端Jedis

jedis 是redis 的java客户端连接包。

百度搜索【maven】进入,maven中央仓库,搜索jedis 获取到,jedis-client的maven引用。

如,下图:

<dependency>

<groupId>redis.clients</groupId>

<artifactId>jedis</artifactId>

<version>2.6.0</version>

</dependency>

注意版本号一定不要出错,否则,可能会和其他jar 有冲突。

redis连接池的构建及调试

要设置为静态类型,是需要保证在tomcat启动的时候就将jedis 连接池加载进来。

Jedis API封装及调试

jedis 是 redis官方推荐的java 客户端,使用java去连接redis的时候,引入jedis相关jar包就可以了。

使用jedis去连接redis ,要手写redis 连接池配置,在项目启动的时候,要初始化连接池。

redis 连接工具类

本示例中展示了两个redis的连接配置,可以执行下面类中mian进行测试,连接两台redis服务。

执行main方法前,先要在阿里云服务器,通过配置文件启动两台端口配置不同的redis服务。

package com.mmall.common;

import java.util.ArrayList;

import java.util.List;

import com.mmall.util.PropertiesUtil;

import redis.clients.jedis.JedisPoolConfig;

import redis.clients.jedis.JedisShardInfo;

import redis.clients.jedis.ShardedJedis;

import redis.clients.jedis.ShardedJedisPool;

import redis.clients.util.Hashing;

import redis.clients.util.Sharded;

/**

* redis 分布式,连接池配置

* @author XW

*

*/

public class RedisShardedPool {

private static ShardedJedisPool pool;//sharded(分片) jedis连接池

private static Integer maxTotal = Integer.parseInt(PropertiesUtil.getProperty("redis.max.total","20")); //最大连接数

private static Integer maxIdle = Integer.parseInt(PropertiesUtil.getProperty("redis.max.idle","20"));//在jedispool中最大的idle状态(空闲的)的jedis实例的个数

private static Integer minIdle = Integer.parseInt(PropertiesUtil.getProperty("redis.min.idle","20"));//在jedispool中最小的idle状态(空闲的)的jedis实例的个数

private static Boolean testOnBorrow = Boolean.parseBoolean(PropertiesUtil.getProperty("redis.test.borrow","true"));//在borrow一个jedis实例的时候,是否要进行验证操作,如果赋值true。则得到的jedis实例肯定是可以用的。

private static Boolean testOnReturn = Boolean.parseBoolean(PropertiesUtil.getProperty("redis.test.return","true"));//在return一个jedis实例的时候,是否要进行验证操作,如果赋值true。则放回jedispool的jedis实例肯定是可以用的。

private static String redis1Ip = PropertiesUtil.getProperty("redis1.ip");

private static Integer redis1Port = Integer.parseInt(PropertiesUtil.getProperty("redis1.port"));

private static String redis1Pwd = PropertiesUtil.getProperty("redis1.pwd");

private static String redis2Ip = PropertiesUtil.getProperty("redis2.ip");

private static Integer redis2Port = Integer.parseInt(PropertiesUtil.getProperty("redis2.port"));

private static String redis2Pwd = PropertiesUtil.getProperty("redis2.pwd");

private static void initPool(){

JedisPoolConfig config = new JedisPoolConfig();

config.setMaxTotal(maxTotal);

config.setMaxIdle(maxIdle);

config.setMinIdle(minIdle);

config.setTestOnBorrow(testOnBorrow);

config.setTestOnReturn(testOnReturn);

config.setBlockWhenExhausted(true);//连接耗尽的时候,是否阻塞,false会抛出异常,true阻塞直到超时。默认为true。

JedisShardInfo info1 = new JedisShardInfo(redis1Ip,redis1Port,1000*2);

info1.setPassword(redis1Pwd);

JedisShardInfo info2 = new JedisShardInfo(redis2Ip,redis2Port,1000*2);

info2.setPassword(redis2Pwd);//设置redis登录密码

List<JedisShardInfo> jedisShardInfoList = new ArrayList<JedisShardInfo>(2);

jedisShardInfoList.add(info1);

jedisShardInfoList.add(info2);

/**

* Hashing.MURMUR_HASH,使用一致性hash算法

*/

pool = new ShardedJedisPool(config,jedisShardInfoList, Hashing.MURMUR_HASH, Sharded.DEFAULT_KEY_TAG_PATTERN);

}

static{

initPool();

}

public static ShardedJedis getJedis(){

return pool.getResource();

}

public static void returnBrokenResource(ShardedJedis jedis){

pool.returnBrokenResource(jedis);

}

public static void returnResource(ShardedJedis jedis){

pool.returnResource(jedis);

}

public static void main(String[] args) {

ShardedJedis jedis = pool.getResource();

for(int i =0;i<10;i++){

jedis.set("key"+i,"value"+i);

}

returnResource(jedis);

System.out.println("program is end");

}

}

pool = new ShardedJedisPool(config,jedisShardInfoList, Hashing.MURMUR_HASH, Sharded.DEFAULT_KEY_TAG_PATTERN);

配置redis 连接池的时候,可以指定 分布式算法 使用:一致性hash算法

Jackson 封装JsonUtil及测试

以前,在用户登录之后,是将一个user对象,存入session中。

Redis 中不能存储对象,故而,需要将user 对象,先序列化为一个string,然后,将这个string 存入 redis中。

将相关序列化,和反序列化的方法,封装在JsonUtil类中。

JsonUtil类代码

可以运行此类中的main方法,进行测试。

package com.mmall.util;

import java.text.SimpleDateFormat;

import org.apache.commons.lang.StringUtils;

import org.codehaus.jackson.map.DeserializationConfig;

import org.codehaus.jackson.map.ObjectMapper;

import org.codehaus.jackson.map.SerializationConfig;

import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;

import org.codehaus.jackson.type.JavaType;

import org.codehaus.jackson.type.TypeReference;

import com.mmall.pojo.TestPojo;

import lombok.extern.slf4j.Slf4j;

/**

* Created by XW

*/

@Slf4j

public class JsonUtil {

private static ObjectMapper objectMapper = new ObjectMapper();

static{

/*1.下面这些参数,会影响对象序列化的行为*/

//对象的所有字段全部序列化为字符串,不管是否有字段为null

objectMapper.setSerializationInclusion(Inclusion.ALWAYS);

//取消默认转换timestamps形式,带时间戳

objectMapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS,false);

//忽略空Bean转json的错误,当user对象转json时,user对象中所有属性为null,转化为json对象也不报异常

objectMapper.configure(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS,false);

//所有的日期格式都统一为以下的样式,即yyyy-MM-dd HH:mm:ss,实体类user中有属性为Date类型,使用此设置能格式化这种类型的格式。

objectMapper.setDateFormat(new SimpleDateFormat(DateTimeUtil.STANDARD_FORMAT));

/*2.下面这些参数,会影响对象反序列化的行为*/

//忽略在json字符串中存在,但是在java对象中不存在对应属性的情况。防止转换抛出错误

objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES,false);

}

/**

* 对象转换为字符串

* @param obj

* @return

*/

public static <T> String obj2String(T obj){

if(obj == null){

return null;

}

try {

return obj instanceof String ? (String)obj : objectMapper.writeValueAsString(obj);

} catch (Exception e) {

log.warn("Parse Object to String error",e);

return null;

}

}

/**

* 返回格式化好的字符串

* @param obj

* @return

*/

public static <T> String obj2StringPretty(T obj){

if(obj == null){

return null;

}

try {

return obj instanceof String ? (String)obj : objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);

} catch (Exception e) {

log.warn("Parse Object to String error",e);

return null;

}

}

/**

* 反序列化方法

* 将字符串转换为T类型对象

* 注意:此方法不能反序列化,集合+泛型类型的字符串,如: List<User>

* @param str

* @param clazz

* @return

*/

public static <T> T string2Obj(String str,Class<T> clazz){

if(StringUtils.isEmpty(str) || clazz == null){

return null;

}

try {

return clazz.equals(String.class)? (T)str : objectMapper.readValue(str,clazz);

} catch (Exception e) {

log.warn("Parse String to Object error",e);

return null;

}

}

/**

* 反序列化方法

* 将字符串转换为T类型对象

* 注意:此方法比上一个强大,能反序列化,集合+泛型类型的字符串,如: List<User>

* List<User> userListObj1 = JsonUtil.string2Obj(userListStr, new TypeReference<List<User>>()

* @param str

* @param typeReference

* @return

*/

public static <T> T string2Obj(String str, TypeReference<T> typeReference){

if(StringUtils.isEmpty(str) || typeReference == null){

return null;

}

try {

return (T)(typeReference.getType().equals(String.class)? str : objectMapper.readValue(str,typeReference));

} catch (Exception e) {

log.warn("Parse String to Object error",e);

return null;

}

}

/**

* 反序列化方法

* 将字符串转换为T类型对象

* 注意:此方法比上一个强大,能反序列化,集合+泛型类型的字符串,如: List<User>

* List<User> userListObj2 = JsonUtil.string2Obj(userListStr,List.class,User.class);

* @param str

* @param collectionClass

* @param elementClasses

* @return

*/

public static <T> T string2Obj(String str,Class<?> collectionClass,Class<?>... elementClasses){

JavaType javaType = objectMapper.getTypeFactory().constructParametricType(collectionClass,elementClasses);

try {

return objectMapper.readValue(str,javaType);

} catch (Exception e) {

log.warn("Parse String to Object error",e);

return null;

}

}

Mall电商项目总结(一)——项目概述的更多相关文章

  1. Java生鲜电商平台-微服务架构概述

    Java生鲜电商平台-微服务架构概述 单体架构存在的问题 在传统的软件技术架构系统中,基本上将业务功能集中在单一应用内,或者是单一进程中.尽管现代化的软件架构理论以及设计原则已推广多年,但实际技术衍化 ...

  2. Mall电商实战项目发布重大更新,全面支持SpringBoot 2.3.0

    1. 前言 前面近一个月去写自己的mybatis框架了,对mybatis源码分析止步不前,此文继续前面的文章.开始分析mybatis一,二级缓存的实现. 附上自己的项目github地址:https:/ ...

  3. Mall电商项目总结(二)——nginx负载均衡配置和策略

    1. nginx配置文件 用户在浏览器上输入,http://www.xwld.site/ 实际上是在访问服务器80端口,nginx 监听80端口,将用户的请求转发到8080和9080端口 . upst ...

  4. Flutter实战视频-移动电商-09.首页_项目结构建立和获取数据

    09.首页_项目结构建立和获取数据 在config下创建service_url.dart 用来配置我们后端接口的配置文件 一个变量存 接口地址,一个接口方法地址 所有后天请求数据的方法都放在这个文件夹 ...

  5. Java 18套JAVA企业级大型项目实战分布式架构高并发高可用微服务电商项目实战架构

    Java 开发环境:idea https://www.jianshu.com/p/7a824fea1ce7 从无到有构建大型电商微服务架构三个阶段SpringBoot+SpringCloud+Solr ...

  6. 电商CRM的痛点在哪里?

    观电商风云,风起云涌,如何寻找新客户及维护老客户,抢占市场,此时迫在眉睫.在大家所认为的CRM就是发发短信,发发邮件等形式去推送活动信息,但在三疯看来,做CRM的关键词是“互动”,而不是简单的促销. ...

  7. 14 微服务电商【黑马乐优商城】:day04-项目搭建(一)

    本项目的笔记和资料的Download,请点击这一句话自行获取. day01-springboot(理论篇) :day01-springboot(实践篇) day02-springcloud(理论篇一) ...

  8. GitHub Vue项目推荐|Vue+Element实现的电商后台管理系统功能丰富

    GitHub Vue项目推荐|mall-admin-web是一个电商后台管理系统的前端项目基于Vue+Element实现 主要包括商品管理.订单管理.会员管理.促销管理.运营管理.内容管理.统计报表. ...

  9. 如何一步一步用DDD设计一个电商网站(二)—— 项目架构

    阅读目录 前言 六边形架构 终于开始建项目了 DDD中的3个臭皮匠 CQRS(Command Query Responsibility Segregation) 结语 一.前言 上一篇我们讲了DDD的 ...

随机推荐

  1. AC日记——Destroying The Graph poj 2125

    Destroying The Graph Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 8356   Accepted: 2 ...

  2. 常用工具篇(二)死链接扫描工具–Xenu

    一个网站上线一段时间之后,可能出现很多的死链接,死链接就是那些打不开的链接,或者是请求是404的,可能是因为有的文件位置移动了,或者有的功能不好使了,可能会影响我们网的功能,我们就要隔一阵扫描一下网站 ...

  3. CCCC L2-024 部落【并查集】

    https://www.patest.cn/contests/gplt/L2-024 首先在一行中输出这个社区的总人数.以及互不相交的部落的个数.随后对每一次查询,如果他们属于同一个部落,则在一行中输 ...

  4. qt使用

    1安装qt软件(.run文件) . chmod 777 qt.....run ./qt...run或sudo ./qt...run(安装目录不一样) 2.sudo gedit .bashrc添加以下内 ...

  5. spring事物,在service层如果进行了异常处理,则不会回滚

    今天进行了事物处理的验证,发现如果在在service层如果进行了异常处理,则不会回滚. 看来异常的处理还是统一放在controller层比较好,service如果是查询方法,出现了异常,就不要做处理了 ...

  6. ConcurrentHashMap如何保证线程安全

    以前看过HashMap的内部实现,知道HashMap是使用Node数组+链表+红黑树的数据结构来实现,如下图所示.但是HashMap是非线程安全,在多线程环境不能够使用. 不过JDK在其并发包中为我们 ...

  7. 邁向IT專家成功之路的三十則鐵律 鐵律十三:IT人理財之道-知足

    身為一位專業的IT人士,工作上不僅要做到滿足興趣與專業熱忱,當然也要做到能夠滿足荷包.現代人賺錢不是問題,但花錢卻出了很大問題,親愛的IT朋友們,請不要將您辛苦賺來的錢花在想要的東西上,實際上需要的卻 ...

  8. 【零基础学习iOS开发】【01-前言】02-准备

    一.程序设计语言 上一讲已经说到:要想开发一款软件,首先得学习一些对应的程序设计语言. 至于iOS开发,须要学习的语言主要有:C.C++.Objective-C. 回到顶部 二.是否须要计算机专业知识 ...

  9. [ssh新闻公布系统三]存储新闻

    一.存储新闻dao方法 在NewsDao.java中新增存储新闻的saveOrupdate方法 public void saveOrupdate(News news){ getSession().sa ...

  10. C#对象实例化

    C#常用的对象实例化有以下几种方式: using System; using System.Collections.Generic; using System.Linq; using System.R ...