P27-項目優化-前後端分離
- 1.為什麼進行前後端分離
- 2.前後端分離開發
-
- 2.1介紹
- 2.2開發流程
- 2.3前端技術棧
-
- 2.3.1開發工具
- 2.3.2技術架構
- 3.Yapi-用來定義接口
-
- 3.1介紹
- 3.2使用
-
- 3.2.1添加項目
- 3.2.2添加分類
- 3.2.3添加接口
- 3.2.4編輯接口
- 3.2.5檢視接口
- 3.2.6導出定義的接口
- 3.2.7導入接口
- 4.Swagger
-
- 4.1介紹
- 4.2使用方式
-
- 4.2.1導入knife4j的maven坐标
- 4.2.2導入knife4j相關配置類-WebMvcConfig
- 4.2.3設定靜态資源,否則接口文檔頁面無法通路-WebMvcConfig
- 4.2.4在LoginCheckFilter中設定不需要處理的請求路徑
- 4.3常用注解
- 5.項目部署
-
- 5.1部署架構
- 5.2部署環境
-
- 5.2.1伺服器A- 192.168.138.100 [192.168.112.100(Linux)自己虛拟機端口]
- 5.2.1伺服器B-192.168.138.101 [127.0.0.1(Windows) 自己ipv4位址]
- 5.2.1伺服器C-172.17.2.94 [(Linux)]
- 5.3部署前端項目
-
- 5.3.1第一步:在伺服器A中安裝Nginx,将dist目錄上傳到Nginx的html目錄下
- 5.3.2修改Nginx配置檔案nginx.conf
- 5.4部署後端項目
-
- 5.4.1第一步:在伺服器B中安裝jdk、git、 maven、MySQL,使用git clone指令将git遠端倉庫的代碼克隆下來
- 5.4.2運作 springboot項目
1.為什麼進行前後端分離
- 開發人員同時負責前端和後端代碼開發,分工不明确
- 開發效率低
- 前後端代碼混合在一個工程中,不便于管理
- 對開發人員要求高,人員招聘困難
2.前後端分離開發
2.1介紹
前後端分離開發,就是在項目開發過程中,對于前端代碼的開發由專門的前端開發人員負責,後端代碼則由後端開發人員負責,這樣可以做到分工明确、各司其職,提高開發效率,前後端代碼并行開發,可以加快項目開發進度。目前,前後端分離開發方式已經被越來越多的公司所采用,成為目前項目開發的主流開發方式。
前後端分離開發後,從工程結構上也會發生變化,即前後端代碼不再混合在同一個maven工程中,而是分為前端工程和後端工程。
2.2開發流程
前後端分離開發後,面臨一一個問題,就是前端開發人員和後端開發人員如何進行配合來共同開發一一個項目?
可以按照如下流程進行:
接口(API接口)一個http的請求,主要就是去定義:
- 請求路徑
- 請求方式
- 請求參數
- 響應資料
等内容。
接口例子
2.3前端技術棧
2.3.1開發工具
- Visual Studio Code
- hbuilder .
2.3.2技術架構
- nodejs
- VUE
- ElementUI
- mock
- webpack 前端打包工具
3.Yapi-用來定義接口
3.1介紹
YApi是高效、易用、功能強大的api管理平台,旨在為開發、産品、測試人員提供更優雅的接口管理服務。可以幫助.開發者輕松建立、釋出、維護API, YApi 還為使用者提供了優秀的互動體驗,開發人員隻需利用平台提供的接口資料寫入工具以及簡單的點選操作就可以實作接口的管理。
YApi讓接口開發更簡單高效,讓接口的管理更具可讀性、可維護性,讓團隊協作更合理。
要使用YApi,需要自己進行部署。
3.2使用
3.2.1添加項目
3.2.2添加分類
3.2.3添加接口
3.2.4編輯接口
請求參數設定
傳回參數設定
3.2.5檢視接口
接口設定好,在編輯裡面設定狀态為完成
3.2.6導出定義的接口
3.2.7導入接口
4.Swagger
4.1介紹
使用Swagger你隻需要按照它的規範去定義接口及接口相關的資訊,再通過Swagger衍生出來的一系列項目和工具,就可以做到生成各種格式的接口文檔,以及線上接口調試頁面等等。
knife4j是為Java MVC架構內建Swagger生成Api文檔的增強解決方案。
<dependency>
<groupld>com.github.xiaoymin</ groupld>
<artifactld>knife4j-spring-boot-starter</ artifactld>
<version>3.0.2</version>
</dependency>
4.2使用方式
4.2.1導入knife4j的maven坐标
<dependency>
<groupld>com.github.xiaoymin</ groupld>
<artifactld>knife4j-spring-boot-starter</ artifactld>
<version>3.0.2</version>
</dependency>
4.2.2導入knife4j相關配置類-WebMvcConfig
package com.jq.config;
import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import com.jq.commom.JacksonObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.cbor.MappingJackson2CborHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.List;
/**
* 配置類,映射靜态資源
*/
@Slf4j
@Configuration
@EnableSwagger2
@EnableKnife4j
public class WebMvcConfig extends WebMvcConfigurationSupport {
/**
* 設定靜态資源映射
* @param registry
*/
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
log.info("開始進行靜态資源映射...");
registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/backend/");
registry.addResourceHandler("/front/**").addResourceLocations("classpath:/front/");
}
/**
* 擴充 Spring Mvc 的消息轉換器
* @param converters
*/
@Override
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
log.info("擴充消息轉換器...");
//建立消息轉換器對象
MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
//設定對象轉換器,底層使用Jackson将Java對象轉換為JSON
messageConverter.setObjectMapper(new JacksonObjectMapper());
//将上面的消息轉換器對象追加到spring MVC架構的轉換器集合中
converters.add(0,messageConverter);
}
@Bean
public Docket createRestApi() {
// 文檔類型
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.jq.controller"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("瑞吉外賣")
.version("1.0")
.description("瑞吉外賣接口文檔")
.build();
}
}
4.2.3設定靜态資源,否則接口文檔頁面無法通路-WebMvcConfig
/**
* 設定靜态資源映射
* @param registry
*/
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
log.info("開始進行靜态資源映射...");
registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/backend/");
registry.addResourceHandler("/front/**").addResourceLocations("classpath:/front/");
}
4.2.4在LoginCheckFilter中設定不需要處理的請求路徑
package com.jq.filter;
import com.alibaba.fastjson.JSON;
import com.jq.commom.BaseContext;
import com.jq.commom.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.AntPathMatcher;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 自定義過濾器
* 檢查使用者是否已經完成登入
*/
@WebFilter(filterName = "loginCheckFilter",urlPatterns = "/*")
@Slf4j
public class LoginCheckFilter implements Filter {
//路徑比對器,支援通配符
public static final AntPathMatcher PATH_MATCHER=new AntPathMatcher();
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request=(HttpServletRequest) servletRequest;
HttpServletResponse response=(HttpServletResponse) servletResponse;
/**
* 1、擷取本次請求的URI
* 2、判斷本次請求是否需要處理
* 3、如果不需要處理,則直接放行
* 4、判斷登入狀态,如果已登入,則直接放行
* 5、如果未登入則傳回未登入結果
*/
//1、擷取本次請求的URI
String requestURI =request.getRequestURI();// /backend/index.html
log.info("攔截到請求:{}",requestURI);
//定義不需要處理的請求路徑
String []urls=new String[]{
"/employee/login",
"/employee/logout",
"/backend/**",
"/front/**",
"/common/**",
"/user/sendMsg",
"/user/login",
"/doc.html",
"/webjars/**",
"/swagger-resources",
"/v2/api-docs"
};
//2、判斷本次請求是否需要處理
boolean check = check(urls, requestURI);
//3、如果不需要處理,則直接放行
if (check){
log.info("本次請求{}不需要處理",requestURI);
filterChain.doFilter(request,response);
return;
}
//4-1、背景管理系統:判斷登入狀态,如果已登入,則直接放行
if(request.getSession().getAttribute("employee")!=null){
log.info("使用者已登入,使用者id為:{}",request.getSession().getAttribute("employee"));
//擷取使用者id
Long empId=(Long) request.getSession().getAttribute("employee");
//調用BaseContext來設定目前使用者登入的id
BaseContext.setCurrentId(empId);
filterChain.doFilter(request,response);
return;
}
//4-2、前端移動端使用者系統:判斷登入狀态,如果已登入,則直接放行
if(request.getSession().getAttribute("user")!=null){
log.info("使用者已登入,使用者id為:{}",request.getSession().getAttribute("user"));
//擷取使用者id
Long userId=(Long) request.getSession().getAttribute("user");
//調用BaseContext來設定目前使用者登入的id
BaseContext.setCurrentId(userId);
filterChain.doFilter(request,response);
return;
}
log.info("使用者未登入");
//5、如果未登入則傳回未登入結果,通過輸出流的方式向用戶端頁面響應資料
response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
return;
}
/**
* 路徑比對,檢查本次請求是否需要放行
* @param urls
* @param requestURI
* @return
*/
public boolean check(String [] urls,String requestURI){
for (String url : urls) {
boolean match = PATH_MATCHER.match(url, requestURI);
if (match){
return true;
}
}
return false;
}
}
4.3常用注解
加入注解後的swagger文檔
5.項目部署
5.1部署架構
5.2部署環境
伺服器:
5.2.1伺服器A- 192.168.138.100 [192.168.112.100(Linux)自己虛拟機端口]
- Nginx:部署前端項目、配置反向代理
- Mysql:主從複制結構中的主庫
5.2.1伺服器B-192.168.138.101 [127.0.0.1(Windows) 自己ipv4位址]
- jdk:運作Java項目
- git:版本控制工具
- maven:項目建構工具
- jar: Spring Boot項目打成jar包基于内置Tomcat運作
- Mysql:主從複制結構中的從庫
5.2.1伺服器C-172.17.2.94 [(Linux)]
- Redis:緩存中間件
5.3部署前端項目
5.3.1第一步:在伺服器A中安裝Nginx,将dist目錄上傳到Nginx的html目錄下
進入nginx目錄下的html目錄
cd /usr/local/nginx/html/
上傳dist目錄
5.3.2修改Nginx配置檔案nginx.conf
記得關閉防火牆,要不然外部浏覽器通路不到
#反向代理配置
location ^~ /api/ {
rewrite ^/api/(.*)$ /$1 break; //url重寫
proxy_pass http://192.168.138.101:8080;
}
自己的配置檔案如下
- 通路的 192.168.112.100
- 反向代理的結果 :192.168.112.100/api/employee/login
- 反向代理URL重寫 :/api/employee/login —》/employee/login
- 後端正常通路是 192.168.137.1:8080/employee/login
5.4部署後端項目
5.4.1第一步:在伺服器B中安裝jdk、git、 maven、MySQL,使用git clone指令将git遠端倉庫的代碼克隆下來
5.4.2運作 springboot項目
- Windows ,直接運作 springboot項目即可
-
Linux環境下,運作 springboot項目
第二步:将reggiesStart.sh檔案.上傳到伺服器B,通過chmod指令設定執行權限.
修改權限#!/bin/sh echo ================================= echo 自動化部署腳本啟動 echo ================================= echo 停止原來運作中的工程 APP_NAME=reggie_take_out tpid=`ps -ef|grep $APP_NAME|grep -v grep|grep -v kill|awk '{print $2}'` if [ ${tpid} ]; then echo 'Stop Process...' kill -15 $tpid fi sleep 2 tpid=`ps -ef|grep $APP_NAME|grep -v grep|grep -v kill|awk '{print $2}'` if [ ${tpid} ]; then echo 'Kill Process!' kill -9 $tpid else echo 'Stop Success!' fi echo 準備從Git倉庫拉取最新代碼 cd /usr/local/javaapp/reggie_take_out echo 開始從Git倉庫拉取最新代碼 git pull echo 代碼拉取完成 echo 開始打包 output=`mvn clean package -Dmaven.test.skip=true` cd target echo 啟動項目 nohup java -jar reggie_take_out-1.0-SNAPSHOT.jar &> reggie_take_out.log & echo 項目啟動完成
Windows下運作springboot,修改圖檔的路徑 如果是在Linux運作springboot,修改圖檔的路徑chmod 777 reggiesStart.sh
# 檔案上傳後儲存路徑 rj: path: /usr/local/img/