Vue-cli3與springboot項目整合打包


一、需求

  
    使用前后端分離編寫了個小程序,前端使用的是vue-cli3創建的項目,后端使用的是springboot創建的項目,部署的時候一起打包部署,本文對一些細節部分進行了說明。
 

二、Vue項目具體配置

 
    (1) vue正常開發使用代理與后台交互,在打包時候,有些配置需要和后端保持一致
 
    (2)配置生產時環境變量: (file:  .env.production),
  .env.production是我自己配置的生產時環境變量,可以自己創建(具體可以參考:vue-cli3環境配置),也可以忽略這個,直接填寫,例如,在axios的配置中,可以直接配置成Axios.defaults.baseURL = '/app_name/v1'
 
NODE_ENV = 'production'
VUE_APP_BASE_URL= /app_name/v1
VUE_APP_CONTEXT=/pre-lcas
VUE_APP_ASSETS=static 

 

  1. VUE_APP_BASE_URL
          用於給所有http請求指定起始路徑,前端項目中使用axios組件支持http請求,在axios的配置文件中指定  Axios.defaults.baseURL = process.env.VUE_APP_BASE_URL , 這樣原本通過代理與后台進行的請求,都會加上`/app_name/v1`,
            例如: 在前端代碼中使用的是: axios.get('/reqUrl/abc')......  向后台發起請求,根據上面配置后,打包后的工程請求路徑會變成 {http://xxx:xx/app_name/v1/reqUrl/abc} 可以通過這個配置,匹配前端請求。
 
  1. VUE_APP_CONTEXT和VUE_APP_ASSETS
        用於設置打包后的成果物相關信息,在配置文件vue.config.js中使用,配置方式如下:
module.exports = {
  // 設置路徑
  publicPath: process.env.VUE_APP_CONTEXT,
  assetsDir: process.env.VUE_APP_ASSETS,
......
}
publicPath和assetsDir的作用可以參考 官網,如果assetsDir不配置,默認會把index.html文件和css等目錄都放到static目錄下,這樣復制springboot項目下會出現無法訪問靜態資源的問題,嘗試了幾種方法,還是將assetsDir配置成static比較好。打包后的資源目錄結構如下:
dist
--static
----css
----fonts
----img
----js
--favicon.ico
--index.html
復制的時候,將static文件夾復制到springboot的/src/main/resource下,將favicon.ico和index.html也復制到static目錄下。如果springboot是多module工程,靜態文件放到啟動文件所在模塊下的resource目錄中。復制后的springboot目錄如下:
/src
--main
--|--java
--|--|--com.xx.xx.WebApplication
--|--resource
--|--|--static
--|--|--|--css
--|--|--|--fonts
--|--|--|--img
--|--|--|--js
--|--|--|--favicon.ico
--|--|--|--index.html
--|--|--application.properties

 

三、springboot項目配置

 
靜態資源復制到springboot后,還是會出現無法訪問資源的問題,需要設置資源訪問規則。
 
具體代碼是:
 
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
        WebMvcConfigurer.super.addResourceHandlers(registry);
    }
  /**
   * 路由過濾,如果路徑中包含‘home’關鍵詞(前端所有路由都包含‘home’)
   * @return
   */
  @Bean
  public FilterRegistrationBean filterRegistration() {
   FilterRegistrationBean<RewriteFilter> registration = new FilterRegistrationBean<>();
   //注冊rewrite過濾器
   registration.setFilter(new RewriteFilter());
   registration.addUrlPatterns("/*");
   registration.addInitParameter(RewriteFilter.REWRITE_TO,"/index.html");
   registration.addInitParameter(RewriteFilter.REWRITE_PATTERNS, "/home/*");
   registration.setName("rewriteFilter");
   registration.setOrder(1);
   return registration;
  }
}

 RewriteFilter.java代碼

import org.springframework.util.StringUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;

/**
 * 過濾后端請求,不屬於后端的請求,交由前端路由處理
 * @author:   2019/11/1 9:50
 * @since: 0.0.1-SNAPSHOT
 * @modified By:
 */
public class RewriteFilter implements Filter {
    /**
     * 需要rewrite到的目的地址
     */
    public static final String REWRITE_TO = "rewriteUrl";

    /**
     * 攔截的url,url通配符之前用英文分號隔開
     */
    public static final String REWRITE_PATTERNS = "urlPatterns";

    /** 配置url通配符 */
    private Set<String> urlPatterns = null;

    private String rewriteTo = null;
    @Override
    public void init(FilterConfig cfg) throws ServletException {
        //初始化攔截配置
        rewriteTo = cfg.getInitParameter(REWRITE_TO);
        String exceptUrlString = cfg.getInitParameter(REWRITE_PATTERNS);
        if (!StringUtils.isEmpty(exceptUrlString)) {
            urlPatterns = Collections.unmodifiableSet(
                    new HashSet<>(Arrays.asList(exceptUrlString.split(";", 0))));
        } else {
            urlPatterns = Collections.emptySet();
        }
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        String servletPath = request.getServletPath();
        //匹配到后端路徑標識,放行,否則,交給前端路由
        if (isMatches(urlPatterns, servletPath)) {
            req.getRequestDispatcher(rewriteTo).forward(req, resp);
        }else{
            chain.doFilter(req, resp);
        }
    }

    @Override
    public void destroy() {

    }

    /**
     * 匹配返回true,不匹配返回false
     * @param patterns 正則表達式或通配符
     * @param url 請求的url
     * @return
     */
    private boolean isMatches(Set<String> patterns, String url) {
        if(null == patterns){
            return false;
        }
        for (String str : patterns) {
            if (str.endsWith("/*")) {
                String name = str.substring(0, str.length() - 2);
                if (url.contains(name)) {
                    return true;
                }
            } else {
                Pattern pattern = Pattern.compile(str);
                if (pattern.matcher(url).matches()) {
                    return true;
                }
            }
        }
        return false;
    }
}
RewriteFilter.java

 

 

四、說明

有的文章在前后端分離后再整合打包這個問題上,都說明了兩個問題,
一個是要保證整合后靜態資源可以被訪問到,這個問題需要確保打包時的路徑,因為如果打包失誤,會在加載index.html時候找不到css/js等資源;
另一個是要保證請求路徑的分離,用戶看到地址欄的是vue-router中的指定路徑,頁面渲染獲取數據使用的是axios請求路徑,后台開放的是服務路徑,一定要確保axios路徑與后台開放的服務路徑匹配上。
 
有的文章中提到,需要后端對router中的路徑進行處理,我測試的過程中,並沒有出現異常,把訪問不到的路徑交給前端處理就行了,前端會統一處理404異常,跳轉到缺省的404錯誤頁面。
 
2019年11月20日 19:49:04修改:
補充了后端對前端路由的處理,前面有相關代碼。 
如果后端不對前端路由進行處理,也就是說明把前端路由交個前端進行處理,正常訪問不會出現問題,如果用戶刷新瀏覽器,會出現404異常,因為后端代碼無法處理前端路由請求。

參考文章:

vue-cli3.0配置開發環境,測試環境,線上環境( https://blog.csdn.net/qq_37055675/article/details/85047451
 
springboot+vue的前后端分離與合並方案( https://my.oschina.net/u/1760791/blog/1577662
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM