Ytmall商城项目

项目简介

​ 由于之前做的ssm+jsp以及转换成springboot的博客项目较为基础,加入的elasticSearch,shiro等部分也只是学习阶段测试能否正常使用,需要一个比较完整的项目来练手学习.于是根据网上的教程,开始尝试搭建一个商城项目.现基本功能已经实现,包括登录,搜索,购物车,下单…

​ 然后这个项目去年由于比较忙,终止了.会慢慢重启然后会把能学到的新东西慢慢运用到这个项目里

项目启动

各模块默认端口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
* vue支持:8080
* 认证auth:8000
* 商品product:8100
* 订单order:8200
* 购物车cart:8300
* 会员user:8400
* 库存服务:8500
* 优惠券coupon:8600
* 网关Gateway:88
* 检索search:20000
* 第三方服务thirdparty:30000
* alibaba服务注册中心nacos:8848
* 分布式事务实现 seata:8091
* linux
* redis: 6379
* elasticsearch :9200
* kibana: 5601
* nginx: 80
* rabbitMQ: 15672
  1. linux,需要安装docker,docker上需要有nginx,elasticsearch(7.4.2),redis,kibana(7.4.2),rabbitmq.

  2. VUE前端 (可以用VScode)

    1. 安装CNPM

    2. 运行终端

      1
      Cnpm install 
    3. 执行 npm run dev

    4. 启动nacos 注册中心

      image-20210225223812179

      浏览器进入8848 端口 账号 密码都是nacos

      image-20210225223835830

      image-20210225223946582

    5. 启动网关微服务和vue support微服务

    6. 启动起来之后 安装mysql, 然后把项目下的sql语句输入…之前备份数据的时候,没有考虑到数据丢失…所以执行完也只有格式

      所以先自己创建一个后台管理员账户密码试着登录先(账号admin 密码admin)

效果展示

VUE后台管理

image-20200915163457565

image-20200915163536717

image-20200915163555984

image-20200915163736775

商城首页

image-20200907234916640

搜索页

image-20200907123216027

商品详情页

image-20200907124100791

image-20200907124158711

image-20200907124138042

购物车页

image-20200907123546877

加入购物车页

image-20200907123513936

结算页

image-20200907124308914

登录页

image-20200907124752811

image-20200907124911811

注册页

image-20200907124638414

说明

项目地址:https://gitee.com/xyingtao/ytmall

项目启动说明:

  1. 需要linux虚拟拟机Docker环境:docker需要redis nginx rabbitmq elasticsearch(7.4.2) kibana(7.4.2)

  2. nginx环境需自行配置 项目静态文件均放置于nginx下 具体文件在静态文件文件夹

各模块详细说明

VUE

身份认证模块

  • 身份认证模块调用用户模块

  • 密码使用 BCryptPasswordEncoder 加密与匹配

    • 注册阶段
    1
    2
    3
    //密码加密
    BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
    String encode = passwordEncoder.encode(vo.getPassword());
    • 登陆阶段
    1
    2
    BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
    boolean matches = passwordEncoder.matches(password, password1);
  • 登录成功 使用session存放用户信息

    1
    session.setAttribute(AuthServerConstant.LOGIN_USER,memberRespVo);

在分布式系统下,需要使用SpringSession

  • 依赖 (之前要保证引入redis相关)
1
2
3
4
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
  • 启动类上要标注
1
2
//整合redis作为session存储
@EnableRedisHttpSession
  • 配置类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Configuration
public class YtmallSessionConfig {

@Bean
public CookieSerializer cookieSerializer() {
DefaultCookieSerializer serializer = new DefaultCookieSerializer();
serializer.setCookieName("YTSESSION");
serializer.setDomainName("ytmall.com");
serializer.setSameSite(null);
serializer.setUseHttpOnlyCookie(false);
return serializer;
}

//序列化器
@Bean
public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
return new GenericJackson2JsonRedisSerializer();
}
}

社交登录OAuth2(微博)

OAuth简介

  • OAuth是一个开放标准,允许用户授权第三方网站访问他们存储在另外服务提供者上的信息,而不需要将用户名和密码提供给第三方网站或分享他们数据的所有内容.

  • OAuth2.0:对于用户相关的OpenAPI(例如获取用户信息,动态同步,照片,日志分享等)为了保护数据的安全和隐私,第三方网站访问用户数据前都需要显示的向用户征求授权

    image-20200824002610585

  • 微博开放平台 微连接 网站连接 立即接入

    image-20200824003915404

  • 在高级设置里面设置回调页面

    image-20200824004407500

    使用code换取access token 码 只能用一次

  • 数据库和实体类中添加 微博登录需要的三个字段

1
2
3
4
5
6
/**
* 微博相关
*/
private String wbuid;
private String accessToken;
private String expiresIn;
  • 根据官网的文档配置controller 远程调用用户模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
@Slf4j
@Controller
public class OAuth2Controller {

@Autowired
MemberFeignService memberFeignService;

//https://api.weibo.com/oauth2/access_token?client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&grant_type=authorization_code&redirect_uri=YOUR_REGISTERED_REDIRECT_URI&code=CODE
//根据官方文档配置
@GetMapping("/oauth2.0/weibo/success")
private String weibo(@RequestParam("code") String code, HttpSession session) throws Exception {
Map<String,String> map = new HashMap<>();
map.put("client_id","***");
map.put("client_secret","***");
map.put("grant_type","authorization_code");
map.put("redirect_uri","http://auth.ytmall.com/oauth2.0/weibo/success");
map.put("code",code);
//1. 根据code 换取access_token
HttpResponse response = HttpUtils.doPost("https://api.weibo.com", "/oauth2/access_token", "post", new HashMap<>(), new HashMap<>(), map);

//2. 判断
if (response.getStatusLine().getStatusCode()==200) {
//如果成功 转成对象
String s = EntityUtils.toString(response.getEntity());
SocialUser socialUser = JSON.parseObject(s, SocialUser.class);
// 如果 是第一次登录 则注册进去(为社交用户生成一个新的账户) 返回的uid 是固定的
//登录或者注册这个社交用户
//远程调用服务验证身份和设置session
}else{
return "redirect:http://auth.ytmall.com/login.html";
}
}else{
return "redirect:http://auth.ytmall.com/login.html";
}
return "redirect:http://ytmall.com";
}
}
  • 用户模块
    • 如果登录过 更新token和过期时间
    • 如果未登录过 新建用户基本信息 存入对应token 过期时间
  • 测试的时候可以使用 Redis Desktop Manager 查看是否存储

订单模块

  • 解决订单提交幂等性问题: 接口幂等性
  • 解决分布式事务问题: 分布式事务
  • 解决库存解锁(最终一致性)问题: RabbitMq
  • 因为订单服务所有操作都要求登录,所以可以在拦截器增加字段 如果调转过来的链接是查询状态的可以不用重新登录
1
2
3
4
5
String requestURI = request.getRequestURI();
boolean match = new AntPathMatcher().match("/order/order/status/**", requestURI);
if (match){
return true;
}

未完待续 更新ing…