1. 程式人生 > >使用Gradle整合SpringBoot+Vue.js-開發除錯與打包

使用Gradle整合SpringBoot+Vue.js-開發除錯與打包

非常感謝兩位作者:

做Java後臺開發的,一般做Java的要做網頁都是用jsp,但我並不喜歡在jsp程式碼中使用jstl標籤,我一直想找一個Java能用的前後端分離的解決方案。目前確定比較好的組合是:前臺頁面用Vue.js,後臺用SpringBoot。但是Vue.js在網上能找到的都是需要Node.js環境進行打包的,這使得不懂Node.js的Java程式設計師望而卻步。

在此之前,為了能用上Vue.js快速開發網頁,我利用Vue.js的非同步元件的特性來載入元件,並配合vue-router來實現元件的檢視切換。這樣子就能用傳統的JavaScript寫法在網頁端用上Vue.js。對於小型的專案是能適用的,但是對於大型的專案組織起來比較麻煩,而且沒有程式碼壓縮、混淆的功能。

在看到kevinz的文章後,我認真研究了,並稍作修改,在這裡記下學習的筆記。

我的開發環境如下:

IDEIntellij IDEA
JDKJava8
Gradle:3.3
Node.js:6.10.1
Vue-CLI:2.8.1

1.Node.js安裝與配置

  1. 到官網下載最新的Node.js安裝
  2. 由於Node.js安裝後,預設的node_modules和快取檔案是存在C盤的,最好是修改成其它盤。
  3. 在其它盤建立Node.js快取資料夾,如:

    E:\_development\nodejs\global 存放例如用`npm install -g express`命令安裝的模組檔案
    E:\_development\nodejs\cache  存放下載快取
  4. 找到【nodejs安裝目錄】/node_modules/npm/npmrc 檔案,用txt開啟,修改配置:

    prefix=E:\_development\nodejs\global  指定全域性安裝的node模組的目錄
    cache=E:\_development\nodejs\cache    指定快取目錄
    registry=https://registry.npm.taobao.org  指定使用國內的淘寶的Node.js映象
  5. 為了測試配置是否成功,執行一下命令npm install -g express安裝一個express試試,Java程式設計師可能不知道,express是Node.js的後端mvc框架,類似Java中的SpringMVC。如果安裝成功,會生成一個E:_developmentnodejsglobalnode_modules目錄,express的檔案就在該目錄下。
  6. 新增環境變數:

    NODE_PATH=E:\_development\nodejs\global\node_modules
  7. Path環境變數加入路徑:

    E:\_development\nodejs\global 加入該路徑,才能使用後面安裝vue-cli後的vue命令

2.vue-cli安裝

vue-cli中cli是command line interface的縮寫,安裝很簡單:npm install -g vue-cli-g是全域性安裝的意思。安裝過程可能比較久。安裝完可以通過vue -V檢視是否安裝成功。如下圖:

3.在IDEA搭建專案框架

  1. 建立整體工程的結構是,先建立一個總工程,叫show,再建立兩個子模組,一個叫server,一個叫web。
  2. 開啟IDEA,File-->New-->Project-->Gradle-->取消勾選Java-->Next。如下圖:
  3. 輸入父工程的資訊,如下圖:
  4. 設定Gradle相關配置,由於網路特殊原因,最好用本地的Gradle庫,配置如下圖:
  5. 設定專案存放路徑,如下圖:
  6. 專案創建出來就除了Gradle的配置檔案,其它什麼都沒有,接下來要建立兩個子工程server和web。show專案建立後如下圖:
  7. 建立server子專案,對著show專案:

    右鍵-->New-->Module-->Gradle-->勾選Java
    -->Next-->ArtifactId填"server"
    -->Next-->Finished
  8. 建立web子專案,對著show專案:

    右鍵-->New-->Module-->Gradle-->勾選Javaweb
    -->Next-->ArtifactId填"web"
    -->Next-->Finished
  9. show總專案的build.gradle檔案修改成如下配置:

    group 'com.gongshi'
    version '1.0'
  10. show總專案的setting.gradle檔案修改成如下配置:

    rootProject.name = 'show'
    include 'server'
    include 'web'
  11. web子專案的build.gradle檔案修改成如下配置:

    plugins {
        id "com.moowork.node" version "1.1.1"
        id 'java'
    }
    //呼叫npm run build命令的Gradle任務
    task npmBuild(type: NpmTask, dependsOn: npmInstall) {
        group = 'node'
        args = ['run', 'build']
    }
    
    //Gradle的java外掛的jar任務,依賴npmBuild,即web子模組打jar包前必須執行npm run build
    jar.dependsOn npmBuild
    
    //呼叫npm run dev
    task npmDev(type: NpmTask, dependsOn: npmInstall) {
        group = 'node'
        args = ['run', 'dev']
    }

    在上面的程式碼中, id "com.moowork.node" version "1.1.1" 一行是加入了一個Gradle外掛,叫gradle-node-plugin,該外掛可以通過呼叫Gradle命令來呼叫node.js的命令或npm的命令。外掛自帶了一些內容的命令,如:gradle npmInstall用於執行npm install命名,另外還有:

    $ gradle npm_install
    $ gradle npm_update
    $ gradle npm_list
    $ gradle npm_cache_clean
    ...
  12. server子專案的build.gradle檔案修改成如下配置:

    plugins {
        id 'org.springframework.boot' version '1.5.2.RELEASE'
        id 'java'
    }
    
    jar {
        baseName = 'server'
        version =  '1.0'
    }
    
    repositories {
        //使用淘寶的maven映象
        maven{ url 'http://maven.aliyun.com/nexus/content/groups/public'}
    }
    
    dependencies {
        compile project(':web')//server模組依賴web模組
        compile("org.springframework.boot:spring-boot-starter-web")
        compile("org.springframework.boot:spring-boot-devtools")
        testCompile("org.springframework.boot:spring-boot-starter-test")
    }

    在上面的程式碼中,需要特別注意的是compile project(':web'),這個設定能在server打包時把web的資源先打包,並作為依賴,加入到server專案生成的jar包中。

13.在IDEA右側找到Gradle的欄目,點選Refresh All Gradle Projects, IDEA會按找各個build.gradle檔案的配置,下載依賴的jar。

到這裡為止,專案的結構搭建好了,下一步是先編寫一下SpringBoot的程式碼,把一個簡單Java後臺跑起來。

4.編寫SpringBoot的後臺

1.建立包com.gongshi,建立類:Application.java。如下:

Application.java:

package com.gongshi;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

@SpringBootApplication
public class Application {

    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) {
        SpringApplication.run(Application.class);
        logger.info("SpringBoot server stated on port: 8080");
    }

    //增加一個SpringMVC的DispatcherServlet,接收前臺/api開頭的請求
    @Bean
    public ServletRegistrationBean apiV1ServletBean(WebApplicationContext wac) {
        DispatcherServlet servlet = new DispatcherServlet(wac);
        ServletRegistrationBean bean = new ServletRegistrationBean(servlet, "/api/*");
        bean.setName("ApiServlet");
        return bean;
    }

}

3.建立包com.gongshi.controller,建立類:AppController.java。如下:

AppController.java:

package com.gongshi.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/app")
public class AppController {
    
    //簡單的後臺介面,用於測試
    @RequestMapping("/info")
    public Object info(){
        Map<String,Object> map = new HashMap<>();
        map.put("info","hello hello hello");
        return map;
    }
    
}

3.在server/src/main/resources目錄下,建立一個staic目錄,建立一個html頁面,用於測試,如下:
index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<h1>Hello Spring Boot</h1>
</body>
</html>

4.暫時註釋掉server/builde.gradle中的compile project(':web')配置(因為web子專案未配置好vue.js相的內容),在IDEA右側Gradle欄目,點選執行server的bootRun任務,bootRun任務會執行Application.java下的main方法。啟動Spring Boot,如下圖:

為了測試後臺是否正常執行,分別訪問一下:

以上三個結果中,需要注意下第1個和第2個。Spring Boot預設會將server/src/main/resources/static下的檔案作為靜態資源,提供給外部訪問。當訪問http://localhost:8080時,發現static有index.html檔案,預設會顯示到瀏覽器端。這就是為什麼1和2的結果是一樣的。

5.編寫Vue.js的前臺

  1. 在這裡前臺使用vue-cli生成前臺的模板。隨便開啟一個資料夾,比如:D:demo,按住shift+右鍵-->在此處開啟命令視窗,即可開啟一個命令列,輸入命令vue init webpack web,其中webpack是用webpack做vue.js的打包工具,web是生成的模板名稱。依次做以下的選擇:
Project name --> web
Project description --> A Vue.js project
Author --> Hello
Vue build --> 回車
Install vue-router ? --> y
Use ESlint to lint your code? --> n
Setup unit tests with Karma + Mocha? --> n
Setup e2e tests with Nightwatch? --> n

2.執行以上步驟後,vue-cli工具就會將專案模板生成到D:demoweb目錄,此時把web目錄下所有檔案拷貝到IDEA的show/web子專案中。如下圖:

3.IDEA下方開啟Terminal命令列終端,執行命令:cd web ,npm install,這樣子npm就會根據package.js中的資訊下載依賴的模組。安裝後show/web/目錄下會出現node_modules目錄。如下圖:

4.此時需要測試一下vue-cli搭建的web子專案是否正確,開啟IDEA右側Gradle欄目,找到npmDev任務,雙擊執行一下,任務執行成功會自動開啟瀏覽器,顯示localhost:8080,顯示Vue的模板頁面。如下圖:

6.修改Vue.js的前臺配置

  1. 因為gradle構建輸出目錄是build,vue-cli生成的模板的構建指令碼的目錄也是build,因此這裡要把構建指令碼的build目錄修改成script:點選show/web/build目錄,shift+F6重新命名,將show/web/build目錄改成script目錄,避免與gradle的構建輸出目錄衝突。
  2. 修改show/web/package.json中與build目錄相關的配置:
  "scripts": {
    "dev": "node build/dev-server.js",
    "build": "node build/build.js"
  },
    改成:
  "scripts": {
    "dev": "node script/dev-server.js",
    "build": "node script/build.js"
  },

3.修改show/web/script/webpack.dev.conf.js中與build目錄相關的配置:

Object.keys(baseWebpackConfig.entry).forEach(function (name) {
  baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
})
    改成:
Object.keys(baseWebpackConfig.entry).forEach(function (name) {
  baseWebpackConfig.entry[name] = ['./script/dev-client'].concat(baseWebpackConfig.entry[name])
})

4.修改show/web/config/index.js中的配置,包括webpack打包輸出位置,以及配置代理避免跨域問題,具體修改項看下面註釋:

show/web/config/index.js:

// see http://vuejs-templates.github.io/webpack for documentation.
var path = require('path')

var assetsRoot = path.resolve(__dirname, '../build/resources/main/static')// <-----1.add
module.exports = {
  build: {
    env: require('./prod.env'),
    index: path.resolve(assetsRoot, 'index.html'),// <-----2.change
    assetsRoot: assetsRoot,// <-----3.change
    assetsSubDirectory: 'assets',// <-----4.change
    assetsPublicPath: '/',
    productionSourceMap: true,
    // Gzip off by default as many popular static hosts such as
    // Surge or Netlify already gzip all static assets for you.
    // Before setting to `true`, make sure to:
    // npm install --save-dev compression-webpack-plugin
    productionGzip: false,
    productionGzipExtensions: ['js', 'css'],
    // Run the build command with an extra argument to
    // View the bundle analyzer report after build finishes:
    // `npm run build --report`
    // Set to `true` or `false` to always turn it on or off
    bundleAnalyzerReport: process.env.npm_config_report
  },
  dev: {
    env: require('./dev.env'),
    port: 3000,// <-----5.change
    autoOpenBrowser: true,
    assetsSubDirectory: 'assets',// <-----6.change
    assetsPublicPath: '/',
    proxyTable: {// <-----7.change
      '/api/**': 'http://localhost:8080'//代理前臺/api開頭的請求,代理到8080埠,spring boot的訪問埠
    },
    // CSS Sourcemaps off by default because relative paths are "buggy"
    // with this option, according to the CSS-Loader README
    // (https://github.com/webpack/css-loader#sourcemaps)
    // In our experience, they generally work as expected,
    // just be aware of this issue when enabling this option.
    cssSourceMap: false
  }
}

5.測試show/web子專案的開發環境。關閉spring boot後臺,在IDEA右側Gradle欄目找到npmDev任務並執行。如果執行成功,會自動開啟瀏覽器顯示http://localhost:3000,並顯示Vue.js的模板頁面,此時找到show/web/src/components/Hello.vue,修改一點內容:

<script>
export default {
  name: 'hello',
  data () {
    return {
      msg: 'Welcome to Your Vue.js App 333333333'//<-----change
    }
  }
}
</script>

開啟瀏覽器檢視http://localhost:3000,如果對應的內容更新了,則表明web子專案的開發環境正確。

如果執行npmDev報錯,有可能是多次執行npmDev命令,有其它Node.js程序佔用了埠,開啟工作管理員關閉即可,如下圖:

5.測試show/web子專案的打包。在IDEA右側Gradle欄目找到npmBuild任務並執行。如果執行成功,webpack打包的前端資源會輸出到show/web/build目錄下,如下圖:

注意:

我把webpack的打包輸出路徑故意設定成build/resources/main/static,這樣子,web子專案打成jar包後,在classpath中的路徑就是/static目錄了,即跟spring boot預設的靜態資源查詢路徑是一樣的。

再者,server子專案依賴web專案(show/server/build.gradle中的compile project(':web')配置),所以server子專案打jar包前會先將web子專案打成jar包,web子專案的jar包中已經包含了webpack輸出的靜態資源。

所以,當server子專案打包後,訪問http://localhost:8080/index.html就能訪問到web子專案webpack打包的輸出的index.html檔案。

注意:
server子專案打包前,請先刪除show/server/src/main/resources/static目錄,避免與web子專案打包過來的檔案重複。

7.開發除錯

  1. 先執行show/server子專案的bootRun任務,啟動Spring Boot
  2. 再執行show/web子專案的npmDev任務,啟動node的開發伺服器
  3. 而在開發前臺頁面時候(對show/web/src目錄下的檔案修改),應該訪問http://localhost:3000/,而不是8080埠,訪問3000埠,即可看到頁面修改的即時效果。

8.打包

執行show/server子專案的build任務,即可完成打包。打包的jar包已經包含show/web子專案的輸出內容。