不使用前后端分离开发了,管理后台用vue nginx发给网关集群,网关再路由到微服务
静态资源放到nginx中
- 依赖
导入thymeleaf依赖、热部署依赖devtools使页面实时生效
achangmall-product/pom.xml
org.springframework.boot spring-boot-devtools true org.springframework.boot spring-boot-starter-thymeleaf
html首页资源index放到achangmall-product下的static文件夹
把index.html放到templates中
- 关闭thymeleaf缓存,方便开发实时看到更新
thymeleaf:
cache: false
suffix: .html
prefix: classpath:/templates/
- web开发放到web包下,原来的controller是前后分离对接手机等访问的,所以可以改成app,对接app应用
com.achang.achangmall.product.web【存放专门用于页面跳转的controller】
com.achang.achangmall.product.app【存放前后端奶粉里的rest风格接口controller】
- 渲染一级分类菜单 刚导入index.html时,里面的分类菜单都是写死的,我们要访问数据库拿到放到model中,然后在页面foreach填入
@Controller
public class IndexController {
@Autowired
private CategoryService categoryService;
//进入商品首页
@GetMapping({"/","/index.html"})
public String indexPage(Model model){
//查出一级分类
List categoryEntityList = categoryService.getLevel1Categorys();
//放入域中
model.addAttribute("categorys",categoryEntityList);
return "index";
}
}
@Override public ListgetLevel1Categorys() { //查询一级分类 return baseMapper.selectList(new QueryWrapper ().eq("cat_level",1)); }
- 页面引入thymeleft名称空间
xmlns:th="http://www.thymeleaf.org"
- 因为我们上面引用了热部署的pom
更新页面后,在当前页面按Ctrl+Shift+F9,进行刷新热部署页面
- 页面遍历菜单数据
- 渲染三级分类菜单
com.achang.achangmall.product.vo.Catelog2Vo
//二级分类vo
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Catelog2Vo {
private String catalog1Id; //一级父分类id
private List catalog3List; //三级子分类
private String id;//二级分类id
private String name;
//三级分类vo 静态内部类
@NoArgsConstructor
@AllArgsConstructor
@Data
public static class Catelog3Vo{
private String catalog2Id;//二级分类id
private String id;//三级分类id
private String name;
}
}
com.achang.achangmall.product.web.IndexController
//index/catalog.json
@ResponseBody
@GetMapping("/index/catalog.json")
public Map> getCatalogJson(){
Map> resultMap = categoryService.getCatelogJson();
return resultMap;
}
com.achang.achangmall.product.service.impl.CategoryServiceImpl
@Override public Map> getCatelogJson() { //查出所有分类 List level1Categorys = getLevel1Categorys(); //分装数据 Map > resultMap = level1Categorys.stream().collect(Collectors.toMap(CategoryEntity::getCatId, v -> { //每一个的一级分类,查到这个一级分类的二级分类 List list = baseMapper.selectList(new QueryWrapper ().eq("parent_cid", v.getCatId())); List catelog2VoList = null; if (!StringUtils.isEmpty(list)) { catelog2VoList = list.stream().map(item -> { Catelog2Vo catelog2Vo = new Catelog2Vo(v.getCatId().toString(), null, item.getCatId().toString(), item.getName()); //封装二级分类的三级分类 List entityList = baseMapper.selectList(new QueryWrapper ().eq("parent_cid", item.getCatId())); if (!StringUtils.isEmpty(entityList)){ List catelog3Vos = entityList.stream().map(m -> { Catelog2Vo.Catelog3Vo catelog3Vo = new Catelog2Vo.Catelog3Vo(item.getCatId().toString(),m.getCatId().toString(),m.getName()); return catelog3Vo; }).collect(Collectors.toList()); catelog2Vo.setCatalog3List(catelog3Vos); } return catelog2Vo; }).collect(Collectors.toList()); return catelog2VoList; } return catelog2VoList; })); return resultMap; }
1、Nginx配置文件
- 新增本地DNS映射
C:WindowsSystem32driversetchosts
192.168.109.101 achangmall.com
测试访问之前的9200端口
- nginx配置文件
server {
listen 80;
server_name achangmall.com;
#charset koi8-r;
#access_log /var/log/nginx/log/host.access.log main;
location / {
#又转回到本机
proxy_pass http://192.168.153.1:10000;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ .php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ .php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param script_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /.ht {
# deny all;
#}
}
- 测试访问http://achangmall.com/
2、Nginx+网关
- nginx配置
upstream achangmall{
server 192.168.153.1:88;
}
location / {
#又转回到本机
# proxy_pass http://192.168.153.1:10000;
proxy_pass http://achangmall;
}
- 但是我们测试访问http://achangmall.com/
nginx转发会丢失掉host中的信息
- 设置nginx在转发的时候保留host信息
proxy_set_header Host $host;
- 再次测试访问,http://achangmall.com,测试成功
- 将nginx路由的网关配置放置在yaml配置最后
- 最终转发流程
3、 压力测试
- Jmeter下载:https://jmeter.apache.org/download_jmeter.cgi
创建测试计划,添加线程组
线程数==用户
ramp-up 多长时间内发送完
添加-取样器-HTTP请求
添加-监听器-查看结果树
添加-监听器-汇总报告
- 优化
SQL耗时越小越好,一般情况下微秒级别
命中率越高越好,一般情况下不能低于95%
锁等待次数越低越好,等待时间越短越好
中间件越多,性能损失越大,大多都损失在网络交互
4、Nginx动静分离
由于动态资源和静态资源目前都处于服务端,所以为了减轻服务器压力,我们将 js、css、img等静态资源放置在Nginx端,以减轻服务器压力
- 项目静态资源搬家
静态文件上传到 mydata/nginx/html/static/index/css,这种格式
mkdir static
修改index.html的静态资源路径,加上static前缀src="/static/index/img/img_09.png"
等等等,给index.html页面中的路径都加上/static/
修改/mydata/nginx/conf/conf.d/gulimall.conf
如果遇到有/static为前缀的请求,转发至html文件夹
location /static/ {
root /usr/share/nginx/html;
}
再次测试访问achangmall.com,成功将静态资源由nginx返回
5、优化三级分类查询
之前是循环查询数据库,导致有多少跟数据库进行io交互;
这里我们减少数据库的交互,一次性查询所有的数据,减少io资源消耗
com.achang.achangmall.product.service.impl.CategoryServiceImpl
@Override public Map> getCatelogJson() { //将数据库的多次交互,转为一次,一次性查询所有数据 List allList = baseMapper.selectList(null); //查出所有分类 List level1Categorys = getParent_cid(allList,0L); //分装数据 Map > resultMap = level1Categorys.stream().collect(Collectors.toMap(CategoryEntity::getCatId, v -> { //每一个的一级分类,查到这个一级分类的二级分类 List list = getParent_cid(allList,v.getCatId()); List catelog2VoList = null; if (!StringUtils.isEmpty(list)) { catelog2VoList = list.stream().map(item -> { Catelog2Vo catelog2Vo = new Catelog2Vo(v.getCatId().toString(), null, item.getCatId().toString(), item.getName()); //封装二级分类的三级分类 List entityList = getParent_cid(allList,item.getCatId()); if (!StringUtils.isEmpty(entityList)){ List catelog3Vos = entityList.stream().map(m -> { Catelog2Vo.Catelog3Vo catelog3Vo = new Catelog2Vo.Catelog3Vo(item.getCatId().toString(),m.getCatId().toString(),m.getName()); return catelog3Vo; }).collect(Collectors.toList()); catelog2Vo.setCatalog3List(catelog3Vos); } return catelog2Vo; }).collect(Collectors.toList()); return catelog2VoList; } return catelog2VoList; })); return resultMap; } private List getParent_cid(List allList,Long parent_cid) { List collect = allList.stream().filter(item -> { return item.getParentCid().equals(parent_cid); }).collect(Collectors.toList()); return collect; // return baseMapper.selectList(new QueryWrapper ().eq("parent_cid", v.getCatId())); }



