文章目录
- 案例导入说明
- 1.安装MySQL
- 1.1.准备目录
- 1.2.运行命令
- 1.3.修改配置
- 1.4.重启
 
- 2.导入SQL
- 3.导入Demo工程
- 3.1.分页查询商品(仔细看代码,很多新的MP编程技巧)
- 3.2.新增商品
- 3.3.修改商品
- 3.4.修改库存
- 3.5.删除商品
- 3.6.根据id查询商品
- 3.7.根据id查询库存
- 3.8.启动
 
- 4.导入商品查询页面
- 4.1.运行nginx服务
- 4.2.反向代理
 
案例导入说明
导入一个现成的IDEA项目工程,但是利用Docker从0开始配置环境,最终达到项目成功运行的目的
此外,我们导入的是一个商品管理的案例,其中包含商品的CRUD功能。我们将来会给查询商品添加多级缓存。
 也即本项目可以用于演示多级缓存。
1.安装MySQL
后期做数据同步需要用到MySQL的主从功能,所以需要在虚拟机中,利用Docker来运行一个MySQL容器。
1.1.准备目录
为了方便后期配置MySQL,我们先准备两个目录,用于挂载容器的数据和配置文件目录:
# 进入/tmp目录
cd /tmp
# 创建文件夹
mkdir mysql
# 进入mysql目录
cd mysql
1.2.运行命令
进入mysql目录后,执行下面的Docker命令:
注意之前别忘了先启动docker
systemctl start docker
docker run \
 -p 3306:3306 \
 --name mysql \
 -v $PWD/conf:/etc/mysql/conf.d \
 -v $PWD/logs:/logs \
 -v $PWD/data:/var/lib/mysql \
 -e MYSQL_ROOT_PASSWORD=1234 \
 --privileged \
 -d \
 mysql:5.7.25
docker run创建一个新容器,并运行他
--name给容器取个名字 (此处给容器取名就叫mysql)
-d后面接一个镜像名称 表示根据哪个镜像创建新容器
-p 宿主机端口:容器端口隔离容器配置绑定端口,否则访问不了
-v 本地目录:容器内的目录本地数据卷挂载到容器内的数据卷上
1.3.修改配置
在/tmp/mysql/conf目录添加一个my.cnf文件,作为mysql的配置文件:
# 创建文件
touch /tmp/mysql/conf/my.cnf
文件的内容如下:
[mysqld]
skip-name-resolve
character_set_server=utf8
datadir=/var/lib/mysql
server-id=1000
1.4.重启
配置修改后,必须重启容器:
docker restart mysql
上面给容器取了名字的好处,这里可以直接使用name启动容器,而非容器id(需要docker ps 或者docker ps -a查一下,比较麻烦)
注意是docker start 不是docker run(创建并运行容器)
查看:
docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Image}}\t{{.Status}}"
进入容器登陆看看:docker exec -it mysql bash mysql -uroot -p1234 show databases;
宿主机无法直接登陆mysql,做了隔离了,找不到该进程:
2.导入SQL
接下来,利用Navicat客户端连接MySQL,然后导入资料提供的sql文件:
链接:https://pan.baidu.com/s/1dv6ydcwaum3tXRnqmCNxmA
提取码:hzan

其中包含两张表:
- tb_item:商品表,包含商品的基本信息
- tb_item_stock:商品库存表,包含商品的库存信息
之所以将库存分离出来,是因为库存是更新比较频繁的信息,写操作较多。而其他信息修改的频率非常低。
- 先创建数据库
  
- 导入数据
  

3.导入Demo工程
下面导入资料提供的工程:

项目结构如图所示:

其中的业务包括:
- 分页查询商品
- 新增商品
- 修改商品
- 修改库存
- 删除商品
- 根据id查询商品
- 根据id查询库存
业务全部使用mybatis-plus来实现,如有需要请自行修改业务逻辑。
3.1.分页查询商品(仔细看代码,很多新的MP编程技巧)
在cn.whu.item.web包的ItemController中可以看到接口定义:
@GetMapping("list")
public PageDTO queryItemPage(
        @RequestParam(value = "page", defaultValue = "1") Integer page,
        @RequestParam(value = "size", defaultValue = "5") Integer size){
        // 一般名称不一致或者需要设置默认值时,才需要用到@RequestParam注解
        // 此注解是接受url参数的  value是前端的name值,映射到后面变量里面 (一般name和形参名不一致时才需要指定)
        // 当然,还可以设置默认值 如此处的defaultValue
    // 分页查询商品
    Page<Item> result = itemService.query() //用query方法,链式编程,好处:不用写lambda条件了
            .ne("status", 3)
            .page(new Page<>(page, size));
    // 查询库存
    List<Item> list = result.getRecords().stream().peek(item -> {
        ItemStock stock = stockService.getById(item.getId());
        item.setStock(stock.getStock());
        item.setSold(stock.getSold());//库存和余量在另一张表 需要一个个查出来然后设置
    }).collect(Collectors.toList());
    // 封装返回
    return new PageDTO(result.getTotal(), list);
}
3.2.新增商品
在cn.whu.item.web包的ItemController中可以看到接口定义:

3.3.修改商品
在cn.whu.item.web包的ItemController中可以看到接口定义:

3.4.修改库存
在cn.whu.item.web包的ItemController中可以看到接口定义:

3.5.删除商品
在cn.whu.item.web包的ItemController中可以看到接口定义:
逻辑删除,修改状态为3 (MP内部有这个机制呀,这里竟然没用)

这里是采用了逻辑删除,将商品状态修改为3
3.6.根据id查询商品
在cn.whu.item.web包的ItemController中可以看到接口定义:

这里只返回了商品信息,不包含库存
3.7.根据id查询库存
在cn.whu.item.web包的ItemController中可以看到接口定义:

3.8.启动
注意修改application.yml文件中配置的mysql地址信息:

需要修改为自己的虚拟机地址信息、还有账号和密码。
修改后,启动服务,访问:http://localhost:8081/item/10001即可查询数据
- 完整Controller代码
package cn.whu.item.web;
import cn.whu.item.service.IItemService;
import cn.whu.item.service.IItemStockService;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import cn.whu.item.pojo.Item;
import cn.whu.item.pojo.ItemStock;
import cn.whu.item.pojo.PageDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.stream.Collectors;
@RestController
@RequestMapping("item")
public class ItemController {
    @Autowired
    private IItemService itemService;
    @Autowired
    private IItemStockService stockService;
    @GetMapping("list")
    public PageDTO queryItemPage(
            @RequestParam(value = "page", defaultValue = "1") Integer page,
            @RequestParam(value = "size", defaultValue = "5") Integer size){
            // 一般名称不一致或者需要设置默认值时,才需要用到@RequestParam注解
            // 此注解是接受url参数的  value是前端的name值,映射到后面变量里面 (一般name和形参名不一致时才需要指定)
            // 当然,还可以设置默认值 如此处的defaultValue
        // 分页查询商品
        Page<Item> result = itemService.query() //用query方法,链式编程,好处:不用写lambda条件了
                .ne("status", 3)
                .page(new Page<>(page, size));
        // 查询库存
        List<Item> list = result.getRecords().stream().peek(item -> {
            ItemStock stock = stockService.getById(item.getId());
            item.setStock(stock.getStock());
            item.setSold(stock.getSold());//库存和余量在另一张表 需要一个个查出来然后设置
        }).collect(Collectors.toList());
        // 封装返回
        return new PageDTO(result.getTotal(), list);
    }
    @PostMapping
    public void saveItem(@RequestBody Item item){
        itemService.saveItem(item);
    }
    @PutMapping
    public void updateItem(@RequestBody Item item) {
        itemService.updateById(item);
    }
    @PutMapping("stock")
    public void updateStock(@RequestBody ItemStock itemStock){
        stockService.updateById(itemStock);
    }
    @DeleteMapping("/{id}")
    public void deleteById(@PathVariable("id") Long id){
        itemService.update().set("status", 3).eq("id", id).update();
    }
    @GetMapping("/{id}")
    public Item findById(@PathVariable("id") Long id){
        return itemService.query()
                .ne("status", 3).eq("id", id)
                .one();
    }
    @GetMapping("/stock/{id}")
    public ItemStock findStockById(@PathVariable("id") Long id){
        return stockService.getById(id);
    }
}
4.导入商品查询页面
商品查询是购物页面,与商品管理的页面是分离的。
部署方式如图:

我们需要准备一个反向代理的nginx服务器,如上图红框所示,将静态的商品页面放到nginx目录中。
页面需要的数据通过ajax向服务端(nginx业务集群)查询。
4.1.运行nginx服务
这里直接使用资料中准备好了的nginx反向代理服务器和静态资源。
链接:https://pan.baidu.com/s/1dv6ydcwaum3tXRnqmCNxmA
提取码:hzan
找到资料的nginx目录:

将其拷贝到一个非中文无空格的目录下,运行这个nginx服务。

运行命令:
start nginx.exe
然后访问 http://localhost/item.html?id=10001即可:

4.2.反向代理
现在,页面是假数据展示的。我们需要向服务器发送ajax请求,查询商品数据。
打开控制台,可以看到页面有发起ajax查询数据:

而这个请求地址同样是80端口,所以被当前的nginx反向代理了。
http://localhost/api/item/10002其中的api一看就知道是nginx.conf里配置的反向代理规则
查看nginx的conf目录下的nginx.conf文件:

其中的关键配置如下:

监听80端口,以/api开头的请求
其中的192.168.150.101是我的虚拟机IP,也就是我的Nginx业务集群要部署的地方:
若你的不一样,如:192.168.141.100 , 手动修改一下

完整内容如下:
#user  nobody;
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    #tcp_nopush     on;
    keepalive_timeout  65;
	#nginx的业务集群,集群里可以做:nginx本地缓存、redis缓存、tomcat查询
    upstream nginx-cluster{
        server 192.168.141.100:8081;
	   server 192.168.141.100:8082;
    }
    server {
        listen       80;
        server_name  localhost;
	location /api {
            proxy_pass http://nginx-cluster;
        }
        location / {
            root   html;
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}
环境都准备好啦,接下来实现nginx集群(部署到linux端)(然后windows端一个nginx做反向代理即可)























