当前位置: 首页 > news >正文

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

一,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-cartdatasource:#type连接池类型 DBCP,C3P0,Hikari,Druid,默认为Hikaritype: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/zmall?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=trueusername: rootpassword: 1234freemarker:suffix: .htmltemplate-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.modelconfiguration:#驼峰命名规则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-gatewaycloud:nacos:discovery:server-addr: localhost:8848gateway:routes:...- id: cart_routeuri: 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 {@Autowiredprivate IOrderFeignService orderFeignService;@RequestMapping("/login.html")public String toLogin(){return "login";}@RequestMapping("/order.html")@ResponseBodypublic 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-gatewaycloud:nacos:discovery:server-addr: localhost:8848gateway:routes:...- id: user_routeuri: 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_savenamespace: session.zmallcleanup-cron: 0 * * * * *store-type: redistimeout: 1800redis:host: localhostport: 6379password: 123456jedis:pool:max-active: 100max-wait: 10max-idle: 10min-idle: 10database: 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 {@Beanpublic CookieSerializer cookieSerializer(){DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();cookieSerializer.setDomainName("zmall.com");cookieSerializer.setCookieName("ZMALLSESSION");return cookieSerializer;}@Beanpublic 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 {
​@Overridepublic 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.lryc.cn/news/2334.html

相关文章:

  • C/C++排序算法(二) —— 选择排序和堆排序
  • 爬虫笔记之——selenium安装与使用(1)
  • STC15单片机软串口的使用
  • Ansible的脚本------playbook剧本
  • 实验5-计算中值及分治技术
  • dbeaver从excel导入数据笔记
  • PyTorch学习笔记:nn.MarginRankingLoss——排序损失
  • 【JavaScript】34_Date对象 ,日期的格式化
  • 计算机视觉 对比学习13篇经典论文、解读、代码
  • MySQL 选择数据库
  • 雅思经验(9)
  • java面试题(二十)中间件redis
  • JavaWEB必知必会-Servlet
  • oralce查找返回不同的值,寻找不同的表(原创)
  • Python-第四天 Python循环语句
  • spring中bean的生命周期(简单5步)
  • 10 个最难理解的 Python 概念
  • 【linux】线程概念
  • Leg转Goh引擎和架设单机+配置登陆器教程
  • idea整合svn
  • 字节青训前端笔记 | 数据可视化基础
  • ROS运行机C++程序,移动
  • C++中编译静态库与动态库
  • shell中sed命令用法
  • 【VictoriaMetrics】VictoriaMetrics启停脚本
  • 高性能网络SIG月度动态:SMC 与 IBM 就扩展协议达成一致,virtio 支持 XDP 新特性
  • 【正点原子FPGA连载】第七章程序固化实验摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南
  • LeetCode-2335. 装满杯子需要的最短总时长【贪心,数学】
  • 基于 oss 框架的音频驱动
  • 【golang】如何定制化zap日志库以及如何使用