开发微服务电商项目演示(三)

news2024/11/23 13:43:26

一,nginx动静分离

第1步:通过SwitchHosts新增二级域名:images.zmall.com

第2步:将本次项目的易买网所有静态资源js/css/images复制到nginx中的html目录下

第3步:在nginx的核心配置文件nginx.conf中新增二级域名images.zmall.com访问映射,用于实现nginx动静分离

注意:修改成功之后,重启nginx服务使其配置生效!!!

当我们访问80端口 或者images.zmall.com时就会自动路由到nginx中html文件中加载静态资源

server{
listen 80;
server_name images.zmall.com;
location / {
root html;
index index.html;
}
}

检测静态资源服务器配置成功

images.zmall.com/css/style.css

第4步:删除zmall-product商品服务和zmall-gateway网关服务下的static静态资源,改用nginx中配置的静态资源

第5步:修改zmall-product商品服务中的templates/common/head.html

<#assign ctx>
    <#--域名,动态请求时需加入该前缀-->
    http://product.zmall.com
</#assign>
<#--采用H5方式的base标签,在整个页面的url地址前加入,用于访问nginx中的静态资源-->
<base href="http://images.zmall.com/"/>

添加二级域名

第6步:分别重启zmall-product、zmall-gateway以及nginx后输入请求地址(启动nacos):

http://zmall.com/product-serv/index.html 走网关的形式

http://product.zmall.com/index.html 走nginx的形式

访问商品服务首页,如下所示:

如果出现IIS7,那么cmd窗口中执行下列指令

net stop w3svc

实现的原理解释:

二,服务调用

创建配置zmall-cart购物车模块

第1步:基于Spring initializr创建zmall-cart购物车模块

第2步:将zmall-order订单模块配置到主模块中

<modules>
    ...
    <module>zmall-cart</module>
    ...
</modules>

第3步:修改pom.xml

<parent>
    <groupId>com.zking.zmall</groupId>
    <artifactId>zmall</artifactId>
    <version>1.0-SNAPSHOT</version>
</parent>
<artifactId>zmall-cart</artifactId>

<dependencies>
    <dependency>
        <groupId>com.zking.zmall</groupId>
        <artifactId>zmall-common</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
</dependencies>

第4步:配置application.yml(端口:8030)

server:
  port: 8030
spring:
  application:
    name: zmall-cart
  datasource:
    #type连接池类型 DBCP,C3P0,Hikari,Druid,默认为Hikari
    type: com.zaxxer.hikari.HikariDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/zmall?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
    username: root
    password: 1234
  freemarker:
    suffix: .html
    template-loader-path: classpath:/templates/
  cloud:
    nacos:
      config:
        server-addr: localhost:8848
#mybatis-plus配置
mybatis-plus:
  #所对应的 XML 文件位置
  mapper-locations: classpath*:/mapper/*Mapper.xml
  #别名包扫描路径
  type-aliases-package: com.zking.zmall.model
  configuration:
    #驼峰命名规则
    map-underscore-to-camel-case: true
#日志配置
logging:
  level:
    com.zking.zmall.mapper: debug

第5步:在启动类上加入@EnableDiscoveryClient

第6步:分别将购物车页面和common/head.html导入到templates目录,并修改head.html中的ctx局部变量

<#assign ctx>
    <#--一级域名,动态请求时需加入该前缀-->
    http://cart.zmall.com
</#assign>
<#--采用H5方式的base标签,在整个页面的url地址前加入,用于访问nginx中的静态资源-->
<base href="http://images.zmall.com/"/>

第7步:在zmall-gateway网关服务中配置购物车的路由转发规则(重启gateway网关服务)

spring:
  application:
    name: zmall-gateway
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    gateway:
      routes:
        ...
        - id: cart_route
          uri: lb://zmall-cart # lb指的是从nacos中按照名称获取微服务,并遵循负载均衡策略
          predicates:
            - Path=/cart-serv/**
          filters:
            - StripPrefix=1
            #此过滤器设置路由过滤器检查的请求属性,以确定是否应发送原始主机头,而不是由 HTTP 客户端确定的主机头
            - PreserveHostHeader

注意:这里要配置过滤器PreserveHostHeader,用于处理重定向时依然已原始主机头发送请求。

第8步:创建CartController并定义请求方法

@Controller
public class CartController {

    @RequestMapping("/cart.html")
    public String toCart(){
        return "buyCar";
    }

    @RequestMapping("/addCart")
    public String addCart(Integer pid,Integer num){
        return "redirect:/cart.html";
    }
}

注意:这里使用redirect重定向方式跳转页面,在SpringCloud gateway路由转发过程中会导致域名跳转变成了http请求方式,所以必须在Gateway网关服务中进行相关的配置。具体请参考第8步的gateway网关路由配置。

<td><a href="http://cart.zmall.com/addCart?pid=${(product.id)!}&num=3" class="b_sure">去购物车结算</a><a href="#" class="b_buy">继续购物</a></td>

创建配置zmall-order订单模块

在zmall-user中通过openfeign方式访问order服务接口

  • 定义openfeign接口

@FeignClient("zmall-order")
public interface IOrderFeignService {
​
    @RequestMapping("/orderUserList")
    List<Order> orderUserList();
}
  • 启动类上设置@EnableDiscoveryClient和@EnableFeignClients

  • 调用接口并测试接口

@Controller
public class UserController {

    @Autowired
    private IOrderFeignService orderFeignService;

    @RequestMapping("/login.html")
    public String toLogin(){
        return "login";
    }

    @RequestMapping("/order.html")
    @ResponseBody
    public List<Order> orderUserList(){
        return orderFeignService.orderUserList();
    }
}

测试链路

http://product.zmall.com/index.html
http://product.zmall.com/product.html?pid=733
http://cart.zmall.com/cart.html

界面能够熊 商品微服务 直接跳转到 购物车微服务中

1.

2.

3.

http://localhost:8010/order.html

调用 用户微服务接口 ,能访问 订单微服务的数据

三,spring session实践

什么是Spring Session

SpringBoot整合Spring-Session的自动配置可谓是开箱即用,极其简洁和方便。这篇文章即介绍SpringBoot整合Spring-Session,这里只介绍基于RedisSession的实战。
Spring Session 是Spring家族中的一个子项目,Spring Session提供了用于管理用户会话信息的API和实现。它把servlet容器实现的httpSession替换为spring-session,专注于解决 session管理问题,默认Session信息存储在Redis中,可简单快速且无缝的集成到我们的应用中
spring session官网地址: https://spring.io/projects/spring-session
Spring Session的特性:
提供用户session管理的API和实现
提供HttpSession,以中立的方式取代web容器的session,比如tomcat中的session
支持集群的session处理,不必绑定到具体的web容器去解决集群下的session共享问题

为什么要使用Spring Session

SpringCloud微服务将一个完整的单体应用拆解成了一个个独立的子服务,而每一个独立的微服务子模块都将部署到不同的服务器中,而服务与服务之间是独立隔离的,这个时候使用要实现服务与服务之间的session会话共享,则需要借助于spring-session框架来解决分布式session管理与共享问题。

错误案例展示

在用户服务zmall-user中编写登录控制器,登录时创建session,并将当前登录用户存储sesion中。

@Controller
public class UserController {
    
    @RequestMapping("/login.html")
    public String toLogin(HttpSession session){
        session.setAttribute("username","admin");
        return "login";
    }
}

在Gateway网关服务中添加用户服务的路由转发规则

spring:
  application:
    name: zmall-gateway
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    gateway:
      routes:
        ...
        - id: user_route
          uri: lb://zmall-user # lb指的是从nacos中按照名称获取微服务,并遵循负载均衡策略
          predicates:
            - Path=/user-serv/**
          filters:
            - StripPrefix=1
            - PreserveHostHeader

在商品服务zmall-product中编写查询控制器,在登录创建session后,使用将sessionId置于cookie中访问。如果没有session将返回错误。

@Controller
public class ProductController {

    @RequestMapping("/index.html")
    public String index(Model model, HttpSession session){
        Object username = session.getAttribute("username");
        System.out.println("**********"+username);
        return "index";
    }
}

测试链路

#1.session信息存储
http://localhost:8010/login.html
#2.session信息获取
http://product.zmall.com/index.html

配置spring-session

在公共模块zmall-common中引入spring-session的pom配置,由于spring-boot包含spring-session的starter模块,所以pom中依赖:注意:公共模块作为所有微服务子模块的依赖支持,如果不在各服务模块中配置redis支持,会导致启动其他微服务时出现报错情况。

<!--redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--spring session-->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
<!--commons-pool2-->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

分别在商品服务zmall-product和用户服务zmall-user中配置application.yml

spring:
  session:
    redis:
      flush-mode: on_save
      namespace: session.zmall
      cleanup-cron: 0 * * * * *
    store-type: redis
    timeout: 1800
  redis:
    host: localhost
    port: 6379
    password: 123456
    jedis:
      pool:
        max-active: 100
        max-wait: 10
        max-idle: 10
        min-idle: 10
    database: 0

重新启动zmall-user和zmall-product服务,先访问:http://zmall.com/user-serv/login.html,然后在访问:http://zmall.com/product-serv/index.html;回到zmall-product模块控制台查看session获取情况。

注意:借助网关微服务内部可以访问,不同二级域名之间不可以访问

四,二级域名问题

测试在用户模块中保存用户信息,然后在产品模块中读取,但是使用二级域名方式访问读取失败

请分别在用户服务和商品服务中该配置类,解决二级域名访问session无效问题。

@Configuration
public class SessionConfig {
    @Bean
    public CookieSerializer cookieSerializer(){
        DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
        cookieSerializer.setDomainName("zmall.com");
        cookieSerializer.setCookieName("ZMALLSESSION");
        return cookieSerializer;
    }
    @Bean
    public RedisSerializer<Object> springSessionDefaultRedisSerializer(){
        return new GenericJackson2JsonRedisSerializer();
    }
}

测试链路

#1.先访问
http://user.zmall.com/login.html
#2.后访问
http://product.zmall.com/index.html

五,用户登录

第1步:在zmall-common公共模块中创建全局异常处理、响应封装类

第2步:在zmall-user模块中定义IUserService及UserServiceImpl

IUserService

public interface IUserService extends IService<User> {
    JsonResponseBody<?> userLogin(UserVo user, HttpServletRequest req, HttpServletResponse resp);
}

UserServiceImpl

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
​
    @Override
    public JsonResponseBody<?> userLogin(UserVo user,
                                         HttpServletRequest req,
                                         HttpServletResponse resp) {
        //1.判断用户账号和密码是否为空
        if(StringUtils.isEmpty(user.getLoginName())||
                StringUtils.isEmpty(user.getPassword()))
            return new JsonResponseBody<>(JsonResponseStatus.USERNAME_OR_PWD_EMPTY);
        //2.根据用户名查询数据对应的用户信息
        User us = this.getOne(new QueryWrapper<User>()
                .eq("loginName", user.getLoginName()));
        //3.判断us用户对象是否为空
        if(null==us)
            return new JsonResponseBody<>(JsonResponseStatus.USERNAME_ERROR);
        try {
            //MD5加密转换处理
            String pwd=MD5Utils.md5Hex(user.getPassword().getBytes());
            //4.判断输入密码与数据库表存储密码是否一致
            if(!us.getPassword().equals(pwd)){
                return new JsonResponseBody<>(JsonResponseStatus.PASSWORD_ERROR);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return new JsonResponseBody<>(JsonResponseStatus.ERROR);
        }
        //5.通过UUID生成token令牌并保存到cookie中
        String token= UUID.randomUUID().toString().replace("-","");
        //将随机生成的Token令牌保存到Cookie中,并设置1800秒超时时间
        CookieUtils.setCookie(req,resp,"token",token,7200);
        //6.将token令牌与spring session进行绑定并存入redis中
        HttpSession session = req.getSession();
        session.setAttribute(token,us);
        return new JsonResponseBody<>(token);
    }
}

第3步:创建UserVo类

@Data
public class UserVo {
    private String loginName;
    private String password;
}

第4步:在UserController中定义用户登录方法

/**
* 用户登陆功能实现
* @return
*/
@RequestMapping("/userLogin")
@ResponseBody
public JsonResponseBody<?> userLogin(UserVo user,
    HttpServletRequest req,
    HttpServletResponse resp){
    return userService.userLogin(user,req,resp);
}

第5步:在前端login.html页面中定义登录js方法

<script>
    $(function(){
        $('.log_btn').click(function(){
            let loginName=$('.l_user').val();
            let password=$('.l_pwd').val();
​
            if(''===loginName){
                alert('请输入用户名!');
                return false;
            }
            if(''===password){
                alert('请输入密码!');
                return false;
            }
            console.log({
                loginName:loginName,
                password:password
            });
            $.post('http://zmall.com/user-serv/userLogin',{
                loginName:loginName,
                password:password
            },function(rs){
                console.log(rs);
                if(rs.code===200){
                    location.href='http://zmall.com/product-serv/index.html';
                }else{
                    alert(rs.msg);
                }
            },'json');
        });
    });
</script>

登录成功后,跳转到商品首页

http://user.zmall.com/login.html

如果用二级域名进行测试,那么需要解决跨域问题;

url: jdbc:mysql://localhost:3306/zmall?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC

成功了!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/337398.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

论文阅读:MINE: Towards Continuous Depth MPI with NeRF for Novel View Synthes

中文标题&#xff1a;基于连续深度多平面和神经辐射场的新视角合成 本文只介绍与NeRF原文不同的部分 创新点 对单一图像进行密集三维重建&#xff0c;完成新视角合成与深度估计的工作。从单个图像生成连续和遮挡绘制的三维重建。MINE借鉴NeRF可以生成连续的深度图像。 解决…

leaflet上传CSV文件,在地图上显示图形(示例代码054)

第054个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+leaflet中加载CSV文件,将图形显示在地图上。CSV(逗号分隔值)文件是一种简单且开放的文件格式,以纯文本形式存储表格数据。 几乎所有电子表格和数据库软件都可以导入/导出这种文件格式。 直接复制下面的 vue+ope…

Navicat无法连接MySQL报错1251的解决方法

日期&#xff1a;2023年2月10日 作者&#xff1a;Commas 签名&#xff1a;(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释&#xff1a;如果您觉得有所帮助&#xff0c;帮忙点个赞&#xff0c;也可以关注我&#xff0c;我们一起成长&#xff1b;如果有不对的地方&#xf…

C++中的智能指针

1.RAII 与引用计数了解 Objective-C/Swift 的程序员应该知道引用计数的概念。引用计数这种计数是为了防止内存泄露而产生的。 基本想法是对于动态分配的对象&#xff0c;进行引用计数&#xff0c;每当增加一次对同一个对象的引用&#xff0c;那么引用对象的引用计数就会增加一次…

[AAAI 2022] TransFG: A Transformer Architecture for Fine-grained Recognition

Contents TransFG ArchitectureExperimentsReferencesTransFG Architecture Overlapping patch split:ViT 是把图片分成一系列不重叠的 patches,作者认为这可能会破坏 discriminative regions. 为了解决上述问题,作者提出使用 Overlapping patch split,划分的 patch 数 N …

消息中间件RabbitMQ

文章目录1. 协议2. RabbitMQ架构原理3.内存管理4.磁盘控制5. RabbiMQ 插件管理6. 死信6.1 死信队列6.2 延时插件7. 高可用集群方案7.1 普通集群模式7.2 镜像集群模式7.3 基于HAproxyKeepalived搭建高可用8.可靠性投递8.1 消息从生产者发送到Broker两种确认机制8.2 消息从Exchan…

数据Kylin(三):Kylin配置

Kylin配置 一、kylin.metadata.url 指定元数据库路径,默认值为 kylin_metadata@hbase 二、kylin.metadata.sync-retries 指定元数据同步重试次数,默认值为 3 三、kylin.env.hdfs-working-dir 指定 Kylin 服务所用的 HDFS 路径,默认值为 /kylin,请确保启动 Kylin 实例的用户…

【面试题】对闭包的理解?什么是闭包?

大厂面试题分享 面试题库后端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★地址&#xff1a;前端面试题库闭包的背景由于js中只有两种作用域&#xff0c;全局作用域和函数作用域&#xff0c;而在开发场景下&#xff0c;将变量暴露在全局作用域下的时候…

云盘满了怎么办?阿里云服务器云盘扩容操作了解一下

1.背景 2.确定扩容云盘类型与控制台操作 3.ECS实例内部扩容操作说明 3.1 ECS实例内部执行扩容分区 3.2 ECS实例内部执行扩容文件系统 1.背景软件应用的数据库所在服务器磁盘使用率已经达到97%,服务器操作实例如下: 一旦使用达到上限,所有的数…

python基于django的 大学生健康管理系统

随着时代的发展,大学生的数量与日预增但是相对的也出现了很多心理问题,大学生因为各类心理引发的社会问题已经受到了很多人的关注,所以如何更好的培养大学生正确的心理健康问题是现在很多大学多面临的一个重要的问题。 系统设置了三种身份的登录,包括管理员,医生和学生。其中管…

SpringBoot 实现 Excel 导入导出,百万数据量,性能爆表!

最近我做过一个MySQL百万级别数据的excel导出功能&#xff0c;已经正常上线使用了。这个功能挺有意思的&#xff0c;里面需要注意的细节还真不少&#xff0c;现在拿出来跟大家分享一下&#xff0c;希望对你会有所帮助。原始需求&#xff1a;用户在UI界面上点击全部导出按钮&…

最近面试了一位5年的测试,一问三不知,还反怼我...

最近看了很多简历&#xff0c;很多候选人年限不小&#xff0c;但是做的都是一些非常传统的项目&#xff0c;想着也不能通过简历就直接否定一个人&#xff0c;何况现在大环境越来 越难&#xff0c;大家找工作也不容易&#xff0c;于是就打算见一见。 在沟通中发现&#xff0c;由…

ISYSTEM调试实践8-winIDEA Analyzer功能1

前面几篇介绍了ISYSTEM的基本调试界面和功能&#xff0c;相比我之前用过的IDE&#xff0c;除了几种断点方式和脚本功能以外&#xff0c;应该都是比较简单&#xff0c;稍微操作一下就可以直接上手&#xff0c;后续我将介绍winIDEA的Analyzer 功能。 1 Analyzer简介 iSYSTEM An…

一文带你为PySide6编译MySQL插件驱动

1.概述 最近使用PySide6开发程序&#xff0c;涉及与MySQL的数据交互。但是qt官方自pyqt5.12&#xff08;记不太清了&#xff09;以后不再提供MySQL的插件驱动&#xff0c;只能自己根据qt的源码编译。不过网上大部分都是qt5的MySQL驱动的编译教程。后来搜到了一个qt6的编译教程…

为什么我需要一个网站?必须拥有网站的 5 个理由

当社交媒体似乎统治了互联网时&#xff0c;您可能会问自己&#xff1a;“我需要一个网站吗&#xff1f;” 答案是肯定的&#xff0c;我在这里告诉你为什么。2019 年&#xff0c;70-80% 的人在访问/购买之前会在线研究公司&#xff0c;同样比例的客户可能会流向没有网站的小企业…

vlookup怎么用详细步骤,看这一篇就够了

1、vlookup函数&#xff1a;使用方法 以下便是vlookup函数&#xff0c;功能、语法和参数用法&#xff1a; excel函数vlookup 2、vlookup函数&#xff1a;查询参数 首先&#xff0c;选中F2单元格&#xff0c;然后在编辑栏输入函数公式&#xff1a;VLOOKUP(E2&#xff0c;B&…

JVM - 认识JVM规范

目录 重识JVM JVM规范作用及其核心 JVM 整体组成 理解ClassFile结构 ASM开发 重识JVM JVM概述JVM&#xff1a; Java Virtual Machine&#xff0c;也就是Java虚拟机所谓虚拟机是指&#xff1a; 通过软件模拟的具有完整硬件系统功能的、运行在一个完全隔离环境中的计算机系统…

InstructGPT

文章目录Abstract 给定人类的命令&#xff0c;并且用人工标注想要的结果&#xff0c;构成数据集&#xff0c;使用监督学习来微调GPT-3。 然后&#xff0c;我们对模型输出进行排名&#xff0c;构成新的数据集&#xff0c;我们利用强化学习来进一步微调这个监督模型。 我们把产…

day35|01背包问题、416. 分割等和子集

01背包问题 有n件物品和一个最多能背重量为w的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品只能用一次&#xff0c;求解将哪些物品装入背包里物品价值总和最大。 例&#xff1a;背包最大重量为4。 物品为&#xff1a; 重量价值物品0115物品…

3种方法设置PDF“打开密码”,总有一种适合你

PDF文件是我们工作中经常用到的文件之一&#xff0c;对于重要的文件&#xff0c;设置“打开密码”是一种很好的保护方式。下面就来说说&#xff0c;设置PDF“打开密码”有哪三种方法&#xff1f; 方法一&#xff1a;在线网站加密 市面上有很多可以直接在线上加密PDF文件的产品…