Table of contents
1. Nginx dynamic and static separation
Create and configure zmall-cart shopping cart module
Create and configure zmall-order order module
Four, spring session actual combat
Five, the second-level domain name problem
1. Nginx dynamic and static separation
Step 1: Add a second-level domain name through SwitchHosts: images.zmall.com
Step 2: Copy all the static resources js/css/images of Yibuy.com in this project to the html directory in nginx
Step 3: Add a second-level domain name images.zmall.com access mapping in the nginx core configuration file nginx.conf to realize the dynamic and static separation of nginx
Note: After the modification is successful, restart the nginx service to make the configuration take effect! ! !
server{
listen 80;
server_name images.zmall.com;
location / {
root html;
index index.html;
}
}
Copy the styles in the project to the html folder in nginx
Detect the success of viewing the static resource server configuration in the browser
http://images.zmall.com/css/style.css
Step 4: Delete the static static resources under the zmall-product commodity service and zmall-gateway gateway service, and use the static resources configured in nginx instead
Step 5: Modify the zmall-product commodity service
templates/common/head.html
<#assign ctx>
<#--域名,动态请求时需加入该前缀-->
http://product.zmall.com
</#assign>
<#--采用H5方式的base标签,在整个页面的url地址前加入,用于访问nginx中的静态资源-->
<base href="http://images.zmall.com/"/>
Step 6: Restart zmall-product, zmall-gateway and nginx respectively and enter the request address: zmall.com/product-serv/index.html to access the product service homepage, as shown below:
Second, service calls
Create and configure zmall-cart shopping cart module
Step 1: Create zmall-cart shopping cart module based on Spring initializr
Step 2: Configure the zmall-order order module into the main module
<modules>
...
<module>zmall-cart</module>
...
</modules>
Step 3: Modify 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>
Step 4: Configure application.yml (port: 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
Step 5: Join on Startup Class@EnableDiscoveryClient
Step 6: Import the shopping cart page and common/head.html into the templates directory, and modify the ctx local variable in head.html
<#assign ctx>
<#--一级域名,动态请求时需加入该前缀-->
http://cart.zmall.com
</#assign>
<#--采用H5方式的base标签,在整个页面的url地址前加入,用于访问nginx中的静态资源-->
<base href="http://images.zmall.com/"/>
Step 7: Configure the routing and forwarding rules of the shopping cart in the zmall-gateway gateway service (restart the gateway gateway service)
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
Note: Here you need to configure the filter PreserveHostHeader, which is used to send requests with the original host header when processing redirection.
Step 8: Create CartController and define request method
@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";
}
}
Note: The redirect redirection method is used here to jump to the page. During the routing and forwarding process of Spring Cloud gateway, the domain name jump will be changed to an http request method, so relevant configuration must be performed in the Gateway gateway service. For details, please refer to the gateway gateway routing configuration in step 8
Step 9: Modify the request method of adding to the shopping cart in the zmall-product module, and direct to the shopping cart
<td><a href="http://cart.zmall.com/addCart?pid=${(product.id)!}&num=3" class="b_sure">去购物车结算</a><a href="#" class="b_buy">继续购物</a></td>
Create and configure zmall-order order module
Step 1: Create zmall-order order module based on Spring initializr
Step 2: Configure the zmall-order order module into the main module
<modules>
...
<module>zmall-order</module>
...
</modules>
Step 3: Modify pom.xml
<parent>
<groupId>com.zking.zmall</groupId>
<artifactId>zmall</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>zmall-order</artifactId>
<dependencies>
<dependency>
<groupId>com.zking.zmall</groupId>
<artifactId>zmall-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
Step 4: Configure application.yml (port: 8040)
server:
port: 8040
spring:
application:
name: zmall-order
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
密码: 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
Step 5: On the startup class join @EnableDiscoveryClient
and@MapperScan({"com.zking.zmall.mapper"})
Step 6: Define the order interface, which can be copied directly from the public module zmall-common
Step 7: Create OrderController and define request interface
@Controller
public class OrderController {
@Autowired
private IOrderService orderService;
@RequestMapping("/orderUserList")
@ResponseBody
public List<Order> orderUserList(){
return orderService.list(new QueryWrapper<Order>()
.eq("userId",18));
}
}
Step 8: Configure the routing and forwarding rules of the shopping cart in the zmall-gateway gateway service (restart the gateway gateway service)
spring:
application:
name: zmall-gateway
cloud:
nacos:
discovery:
server-addr: localhost:8848
gateway:
routes:
...
- id: order_route
uri: lb://zmall-order # lb指的是从nacos中按照名称获取微服务,并遵循负载均衡策略
predicates:
- Path=/order-serv/**
filters:
- StripPrefix=1
- PreserveHostHeader
service call
Access the order service interface through openfeign in zmall-user
Define the openfeign interface
@FeignClient("zmall-order")
public interface IOrderFeignService {
@RequestMapping("/orderUserList")
List<Order> orderUserList();
}
-
Start class settings
@EnableDiscoveryClient
and@EnableFeignClients
-
Call the interface and test the interface
@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();
}
}
test link
http://product.zmall.com/index.html
http://product.zmall.com/product.html?pid=733
http://cart.zmall.com/cart.html
The interface can jump directly from the commodity microservice to the shopping cart microservice
Call the user microservice interface to access the data of the order microservice
Four, spring session actual combat
What is Spring Session
SpringBoot's automatic configuration of Spring-Session integration can be described as out-of-the-box, extremely concise and convenient. This article introduces SpringBoot's integration of Spring-Session. Here we only introduce the actual combat based on RedisSession.
Spring Session is a sub-project of the Spring family. Spring Session provides APIs and implementations for managing user session information. It replaces the httpSession implemented by the servlet container with spring-session, focusing on solving session management problems. The default session information is stored in Redis, which can be easily, quickly and seamlessly integrated into our applications
Spring session official website address: Spring Session
Features of Spring Session:
-
Provide API and implementation of user session management
-
Provide HttpSession to replace the session of the web container in a neutral way, such as the session in tomcat
-
Support cluster session processing, without binding to a specific web container to solve the session sharing problem under the cluster
Why use Spring Session
SpringCloud microservice disassembles a complete monolithic application into independent sub-services, and each independent micro-service sub-module will be deployed to a different server, and services are independently isolated from each other. At this time, to implement session session sharing between services, you need to use the spring-session framework to solve the problem of distributed session management and sharing.
Configure spring-session
Introduce the pom configuration of spring-session in the public module zmall-common. Since spring-boot includes the starter module of spring-session, the pom depends on: Note: the public module is supported as a dependency of all microservice submodules. If it is not in each service Configuring redis support in the module will cause errors when starting other microservices.
<!--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>
Configure application.yml in product service zmall-product and user service zmall-user respectively
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
Restart zmall-user and zmall-product services, first visit: http://zmall.com/user-serv/login.html , then visit: http://zmall.com/product-serv/index.html ; Go back to the zmall-product module console to check the session acquisition.
Note: It can be accessed internally with the help of the gateway microservice, but cannot be accessed between different second-level domain names
Five, the second-level domain name problem
The test saves user information in the user module, and then reads it in the product module, but the access and reading fails using the second-level domain name
Please configure this class in user service and commodity service respectively to solve the problem of invalid access session of the second-level domain name.
@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();
}
}
test link
#1. First visit
http://user.zmall.com/login.html
#2. Then visit
http://product.zmall.com/index.html
user login
Step 1: Create global exception handling and response encapsulation classes in the zmall-common public module
Step 2: Define IUserService and UserServiceImpl in the zmall-user module
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);
}
}
Step 3: Create UserVo class
@Data
public class UserVo {
private String loginName;
private String password;
}
Step 4: Define User Login Method in UserController
/**
* 用户登陆功能实现
* @return
*/
@RequestMapping("/userLogin")
@ResponseBody
public JsonResponseBody<?> userLogin(UserVo user,
HttpServletRequest req,
HttpServletResponse resp){
return userService.userLogin(user,req,resp);
}
Step 5: Define the login js method in the front-end login.html page
<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>
After successful login, jump to the product home page
http://zmall.com/user-serv/login.html
If a second-level domain name is used for testing, then cross-domain issues need to be resolved;
url: jdbc:mysql://localhost:3306/zmall?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC