傳統(tǒng)JavaEE集成Vue

0.簡介

現(xiàn)在的開發(fā)都是講究的是前后端的分離,但是有時候一些傳統(tǒng)的老項目用的技術(shù)十分的不順手,接下來講一講我是如何把Vue框架集成到老項目中去的

1.項目環(huán)境配置:

  • 后端:SSH
  • 前端:npm,webpack vue全家桶

首先來一個整個項目的截圖

傳統(tǒng)項目的結(jié)構(gòu)圖

想必大家對這個結(jié)構(gòu)已經(jīng)十分的了解了,這里簡單的介紹下這個目錄的結(jié)構(gòu):

  • .settings,.classpath,.project都是Eclipse里面的配置問你件
  • adf , res ,core,metedata 是關(guān)聯(lián)的其他項目的源碼
  • metedata是代碼生成器
  • src 是以SSH為框架的后臺代碼
  • WebRoot是前端代碼

吐:下,這個就是老舊的JavaWeb項目,adf ,core,等都是引入的外部的的項目,這些東西是特喵的本可以打成jar包的!


2.理清楚思路:

來來來,先整理一下這個思路

在整個項目中,我們最關(guān)心的問題就是這個開發(fā)的流程怎么走,首先,明確一下開發(fā)的流程:我這里采取從前到后的方式:即由一串url說起:如 http://127.0.0.1:8080/satellite_image//index/index.jsp ,這個是指向的是index.jsp,即index.jsp是整個頁面的入口,index.jsp主要的功用是分為兩個部分,1是通過域?qū)ο笙騤sp頁面里面進行傳值,而作為整個頁面的容器,即承載html,那么此時的html和部署在ngix上的純前端頁面就沒有什么區(qū)別了,我們只需要把npm相關(guān)配置文件丟在WebRoot的根目錄下即可,說白了,就是整個把整個純前端應(yīng)用限制在了WebRoot這么個文件夾下

前端需要分離的部分只能放到WebRoot下進行開發(fā),開發(fā)的流程與傳統(tǒng)的開發(fā)流程也沒有實質(zhì)性的區(qū)別:即是這樣的,我們所有的jsp都要引入一個關(guān)鍵的*.js文件,作為整個文件的操作入口文件,然后再根據(jù)這個文件的模塊,利用js模塊化的思想和Vue模塊化的思想將整個頁面進行分隔,

先上個圖:


重點關(guān)注的前端里面的東西

build文件夾是存放編譯之后的js文件,css是指樣式文件,images是放置圖片的,js是老舊項目原始的文件,懶得管了,js-es6才是我們的重頭戲,重點編寫的文件,其中api是用來搞數(shù)據(jù)操作交互的和其他操作,里面封裝的Data.js就是重點通過ajax與服務(wù)器端的數(shù)據(jù)進行交互的,然后還有一些地圖處理的api啊之類的,components是放置的Vue組件了,啊這些就是前端需要搞的知識點兒了,啊這里的就不詳細介紹了,,我們重點關(guān)注的是流程的走通對不對,

3.正文:

其實吧,最重點的還是特喵的npm那一堆配置文件


,在實際開發(fā)的時候,在npm下就跑到Webroot目錄下,跑npm run dev 即可以進行熱重載的開發(fā),用npm run build-product進行最終文件的壓縮,混淆之類的.

下面針對這些文件進行簡單的介紹一下,先從npm的命令說起:

看一下package.json這么文件,他是整個前端項目的核心組件和文件(復(fù)制過去記得把注釋去掉):

{
  "name": "mzb",  //項目的名稱
  "version": "0.1.0",//版本號
  "private": true, //私有項目?
  "dependencies": { //項目中實打?qū)嵭枰玫降牡谌讲寮?框架之類的,這些東西說白了,是項目的文件,或者是入口js文件需要用的,需要用的,會編譯進去代碼的
  "babel-runtime": "^6.26.0",//運行時,墊片庫,貌似沒有用到,它的作用是,配合通過babel-plugin-transform-runtime自動重寫你的promise等原型對象。但是它不會模擬內(nèi)置對象原型上的方法,比如Array-prototype.find,
  "es5-shim": "^4.5.10",//解決ie8以下的問題,這里投機了,由于入口文件都是import 而這個庫只能用require,所以我編譯了兩次(*/ω\*),在編譯完第一次之后,自動注入require('shim/eshim')然后再編譯一次
  "sweetalert2": "^7.8.4",//甜美的彈出框
  "vue": "^2.5.13",//
  "vuex": "^3.0.1" //
  },
  "scripts": { // 輸入 npm run 腳本時,所能執(zhí)行的命令結(jié)合,在執(zhí)行腳本的時候是可以指定一些參數(shù)的,相當于cmd中進行執(zhí)行命令,多個命令之間用 && 進行分隔
  "test": "echo \"Error: no test specified\" && exit 1",
  "start": "webpack",//執(zhí)行webpack的命令
  "server": "webpack-dev-server --open",
  "dev": "webpack-dev-server --devtool eval-source-map --progress --colors --hot --inline ", //執(zhí)行熱更新開發(fā)者模式
  "build": "webpack --config ./webpack.config.js --progress",
  "build-product": "Set NODE_ENV=production && webpack --config ./webpack.production.config.js --progress && npm run build-product-compatible-ie ",
  "build-product-compatible-ie": "webpack --config ./[webpack.compatible-ie.config.js](http://webpack.compatible-ie.config.js/) --progress"
  },
  "devDependencies": {//這些都是插件,說白了,是編譯器需要用到的,是webpack.js需要用到的
  "babel-cli": "^6.26.0",//沒用到
  "babel-core": "^6.26.0",//貌似和babel-profill有關(guān),待研究
  "babel-loader": "^7.1.2",//必須要有的轉(zhuǎn)碼器啦
  "babel-plugin-transform-runtime": "^6.23.0",//配合上述的進行工作滴
  "babel-polyfill": "^6.26.0", //用于解決低版本瀏覽器api不全的問題,加入之后可以為所欲為的使用高級的api,在文件的頭部統(tǒng)一使用 import 'babel-polyfill'
  "babel-preset-es2015": "^6.24.1",//轉(zhuǎn)成es5的語法 配合bable-loader
  "babel-preset-es2015-loose": "^8.0.0",//es5語法的loose模式 配合bable-loader
  "babel-preset-latest": "^6.24.1",//當前階段最新的語法 配合bable-loader
  "babel-preset-stage-3": "^6.24.1",//當前的語法 配合bable-loader
  "babel-register": "^6.26.0",//待研究,貌似沒用到
  "babelify": "^7.3.0",//待研究,貌似沒用到
  "compression-webpack-plugin": "^1.1.3",//gzip壓縮插件
  "css-loader": "^0.28.7",//編譯css文件的
  "es3ify-loader": "^0.2.0",//解決ie8-,主要是將訪問方式統(tǒng)一抓變成object['prop']的形式
  "eslint-loader": "^1.9.0",//代碼檢查工具
  "style-loader": "^0.18.2",//編譯樣式文件和css-laoder配合,待研究
  "vue-loader": "^13.3.0",//編譯*.vue組件的
  "vue-style-loader": "^3.0.1",//配合vue-laoder
  "vue-template-compiler": "^2.5.2",//配合vue-laoder
  "webpack": "^3.6.0",//打包工具啦
  "webpack-dev-server": "^1.14.1"http://熱更新用到的服務(wù)器啦
    }
}

詳解開發(fā)模式下的webpack.config.js,即 執(zhí)行npm run dev ,或者npm run build都發(fā)生了什么事情

看文件.babelre

{
"presets": [["es2015",{"loose":false}],["stage-3"]], //指定轉(zhuǎn)碼時,代碼所需要識別的高級語法有哪些
"plugins": [     //轉(zhuǎn)碼插件
  "transform-runtime",//待研究
  "transform-es2015-classes"]//轉(zhuǎn)es6里面的class語法,(其實吧,我覺得只用第一個就可以了,待研究)
}

看文件webpack.js

//這里用到的就是nodejs里面的內(nèi)容和語法了,遵循CommonJS的規(guī)范
const path = require('path')
const webpack = require('webpack'); //使用webpack自帶的插件
module.exports = {
devtool: 'eval-source-map', //調(diào)試時使用的source map 方便快速查找文件
entry: [
    "webpack-dev-server/client?[http://localhost:3000](http://localhost:3000/)",
    "webpack/hot/only-dev-server",
    __dirname + '/index/js-es6/index.js'
], //入口文件  【注意:__dirname 是node.js中的一個全局變量,它指向當前執(zhí)行腳本所在的目錄,故多用于構(gòu)建工具的腳本中】
output: {
    path: __dirname + '/index/build', //輸出的路徑
    filename: 'index.js' //輸出的文件名
    // publicPath: '[http://localhost:3000/](http://localhost:3000/)'
},
module: { //多個依賴模塊,如babel,react,laod等模塊
    rules: [ //定義loader的規(guī)則,表示如何處理指定格式的拓展文件
        {
            test: /(\.js|\.jsx)$/,//解析的后綴
            use: {
                loader: 'babel-loader'//解碼器
            },
            exclude: /node_modules/ //自定哪些文件不搞
        },
        {
            test: /(\.css)$/,
            use: [
                { loader: 'style-loader' },
                {
                    loader: 'css-loader',
                    options: { modules: true }
                }
            ]
        },
        {
            test: /(\.vue)$/,
            use: [
                { loader: 'vue-loader' }
            ]
        }
    ]
},
resolve: { alias: { 'vue': 'vue/dist/vue.js' } },//這個是使用完整版,而不只是運行時的vue
plugins: [new webpack.HotModuleReplacementPlugin()], //熱加載插件
devServer: {//這個就6了,這個是保證能在tomcat下,即同一個域下,實現(xiàn)熱加載,在執(zhí)行代理時,為保證符合代理的預(yù)期效果,可以到tomcat下把需要代理的文件刪掉,目前也就只能代理的是這么個入口文件
    port: 3000, //代理服務(wù)器的端口
    proxy: {
        '**': {
            target: '[http://localhost:8080](http://localhost:8080/)', //代理的 服務(wù)器地址,
            secure: false,
            prependPath: false
        }
    },
    publicPath: '[http://localhost:3000/satellite_image/index/build/](http://localhost:3000/satellite_image/index/build/)',//代理的入口文件的地址,詳細的路徑呀
    historyApiFallback: true
  }
}

看文件webpack-inject-js-plugin.js

/*
在編譯之后的腳本之后,往其頭部添加一些引入的庫
用途:多用于連續(xù)打包,在下一次打包之前,引入必要的js庫
Author zgy
*/
"use strict";
const ConcatSource = require("webpack-sources").ConcatSource;
const ModuleFilenameHelpers = require("./node_modules/webpack/lib/ModuleFilenameHelpers");
const injectScript = (str) => {
    if (!str.includes("\n")) return `${str} \n`;
    return `${str.split("\n").join("\n  ")}\n`;
};

class InjectScript {
constructor(options) {
    if (arguments.length > 1)
        throw new Error("腳本注入插件只能傳入一個參數(shù)");
    if (typeof options.banner === "object") {
        options.banner = options.banner.map(item => `require('${item}');`).join('\n');
    }
    console.log(options.banner);
    if (typeof options === "string")
        options = {
            banner: `require('${options}')`
        };
    this.options = options || {};
    this.banner = this.options.raw ? options.banner : injectScript(options.banner);
    console.log(this.banner);
}
apply(compiler) {
    const options = this.options;
    const banner = this.banner;
    console.log("apply-->"+banner);
    compiler.plugin("compilation", (compilation) => {
        compilation.plugin("optimize-chunk-assets", (chunks, callback) => {
            chunks.forEach((chunk) => {
                if (options.entryOnly && !chunk.isInitial()) return;
                chunk.files
                    .filter(ModuleFilenameHelpers.matchObject.bind(undefined, options))
                    .forEach((file) => {
                        let basename;
                        let query = "";
                        let filename = file;
                        const hash = compilation.hash;
                        const querySplit = filename.indexOf("?");
                        if (querySplit >= 0) {
                            query = filename.substr(querySplit);
                            filename = filename.substr(0, querySplit);
                        }
                        if (filename.indexOf("/") < 0) {
                            basename = filename;
                        } else {
                            basename = filename.substr(filename.lastIndexOf("/") + 1);
                        }
                        const comment = compilation.getPath(banner, {
                            hash,
                            chunk,
                            filename,
                            basename,
                            query,
                        });
                        console.log("apply-->comment-->"+comment);
                        console.log("apply-->file-->"+compilation.assets[file]);
                        return compilation.assets[file] = new ConcatSource(comment, "\n", compilation.assets[file]);
                    });
            });
            callback();
        });
    });
  }
}
module.exports = InjectScript;

看文件npm run build-product 發(fā)生了什么,重頭戲,webpack.compatible-ie.config.js和webpack.production.config.js

看文件webpack.production.config.js

// webpack.production.config.js
const webpack = require('webpack');
const InjectScript = require('./webpack-inject-js-plugin.js');
module.exports = {
entry: [
    __dirname + '/index/js-es6/index.js'
], //入口文件  【注意:__dirname 是node.js中的一個全局變量,它指向當前執(zhí)行腳本所在的目錄,故多用于構(gòu)建工具的腳本中】
output: {
    path: __dirname + '/index/build', //輸出的路徑
    filename: 'index.js' //輸出的文件名
},
module: {
    rules: [{
            test: /(\.jsx|\.js)$/,
            use: {
                loader: "babel-loader"
            },
            exclude: /node_modules/
        },
        // {
        //     test: /(\.js)$/,
        //     use: {
        //         loader: 'es3ify-loader',
        //     }
        // },
        {
            test: /(\.vue)$/,
            use: [
                { loader: 'vue-loader' }
            ]
        }
    ]
},
plugins: [
    // new webpack.optimize.OccurrenceOrderPlugin(),
    /*
     *目前需要解決的是ie中的Object.defineProperty,根據(jù)[http://www.aliued.com/?p=3240](http://www.aliued.com/?p=3240) ,暫用得解決方案是轉(zhuǎn)碼再轉(zhuǎn)碼
     *即先webpack轉(zhuǎn)碼一次通用的.js文件,然后注入腳本require('es5-shim')等包,再進行另外一次webpack進行打包轉(zhuǎn)碼
     */
    // new InjectScript({banner:['es5-shim','es5-shim/es5-sham']}),//處理es9以下的瀏覽器api問題,兼容ie9暫時不用
    new webpack.DefinePlugin({
        'process.env': {
            NODE_ENV: '"production"'
        }
    }),
    new webpack.optimize.UglifyJsPlugin({ //混淆插件,其實如果不去兼容ie的即使用 InjectScript注入插件,則可以直接和下面這個文件的內(nèi)容進行合并
        compress: {
            properties: false,
            warnings: false
        },
        output: {
            beautify: true,
            quote_keys: true
        },
        mangle: {
            screw_ie8: false
        },
        sourceMap: false
    })
    ///配置在了Comatible-ie-config.js里面了
    // new CompressionWebpackPlugin({ //gzip 壓縮
    //     asset: '[path].gz[query]',
    //     algorithm: 'gzip',
    //     test: new RegExp(
    //         '\\.(js|css)$' //壓縮 js 與 css
    //     ),
    //     threshold: 10240,
    //     minRatio: 0.8
    // })
],
  resolve: { alias: { 'vue': 'vue/dist/vue.min.js' } }
 };

webpack.compatible-ie.config.js,其實如不要使用注入引入的插件,則不要這樣子搞,合并即可

//其實這個文件才是最后執(zhí)行的,哈!

// webpack.production.config.js
const webpack = require('webpack');
const CompressionWebpackPlugin = require('compression-webpack-plugin');
module.exports = {
entry: [
    __dirname + '/index/build/index.js'
], //入口文件  【注意:__dirname 是node.js中的一個全局變量,它指向當前執(zhí)行腳本所在的目錄,故多用于構(gòu)建工具的腳本中】
output: {
    path: __dirname + '/index/build', //輸出的路徑
    filename: 'index.js' //輸出的文件名
},
module: {
    rules: [
        {
            test: /(\.js)$/,
            use: {
                loader: 'es3ify-loader',
            }
        }
    ]
},
plugins: [
    new webpack.BannerPlugin('版權(quán)所有,翻版必究'),
    // new webpack.optimize.OccurrenceOrderPlugin(),
    new webpack.DefinePlugin({
        'process.env': {
            NODE_ENV: '"production"'
        }
    }),
    new webpack.optimize.UglifyJsPlugin({
        compress: {
            properties: false,
            warnings: false
        },
        output: {
            beautify: false,
            quote_keys: true
        },
        mangle: {
            screw_ie8: false
        },
        sourceMap: false
    }),
            ///配置在了Comatible-ie-config.js里面了
    new CompressionWebpackPlugin({ //gzip 壓縮
        asset: '[path].gz[query]',
        algorithm: 'gzip',
        filename(oldFileName){
            // 符合公司框架的解析規(guī)則
            return oldFileName.substring(0,oldFileName.indexOf("."))+".gzjs";
        },
        test: new RegExp(
            '\\.(js|css)$' //壓縮 js 與 css
        ),
        threshold: 10240,
        minRatio: 0.8
    })
]
};

綜上所述,以上的開發(fā)流程是這樣子的

  1. 首先新建傳統(tǒng)的javaeb項目,maven也可以啦
  2. 在WebRoot下部署node環(huán)境,即編寫上述的那些個包之類的,是實際的項目發(fā)布時,是不需要/node_moudle/這個文件夾的
  3. 建立入口html或者jsp
  4. 新建入口.js,記得抽出一個文件單獨處理與服務(wù)器的數(shù)據(jù)交互工作
  5. 在html中引入這個編譯之后的入口文件,入口引入的方式不同,熱加載的方式也不同,即webServer中,publicPath需要變一變
  6. 編寫webpack的配置文件,指定入口出口文件啊,配置webserver等
  7. 在實際部署時,一定要記得跑product.config,讓js文件該壓縮的壓縮,該混淆的混淆

其實上面的那些不看也可以!

  • 第一步:把這些npm相關(guān)的文件丟到webroot目錄下

  • 第二步:配置好jsp里面的入口*.js

  • 第三步,修改webpack.config里面的入口出口參數(shù),

  • 第四步:到WebRoot目錄下:執(zhí)行npm run dev,部署的時候執(zhí)行npm run build-product

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 寫在前面 知道Vue已經(jīng)有“一段”時間了,粗枝大葉的了解了點,因為當時資料比較少,正式項目中也沒有開始用到,...
    我自靜默向韶華閱讀 541評論 2 2
  • 疑問點 之前開始學(xué)習(xí)Vue時,老是搞不清楚為什么有的時候是:v-bind:class="dynamicClass"...
    放風箏的小小馬閱讀 542評論 0 0
  • 代碼部分請下載本文代碼閱讀,代碼均能正常運行并有詳細的注釋。 本文代碼下載地址 概述 前端開發(fā)近況 需求依然旺盛,...
    每一天都是開始閱讀 7,720評論 3 36
  • 綁定數(shù)據(jù) 一個 Vue 的實例對應(yīng)一個 element,數(shù)據(jù)通綁定的方式,在 element 中通過 {{變量名}...
    yangxg閱讀 264評論 0 0
  • 據(jù)說vue最偉大的功能就是組件啦~ 我就是把官網(wǎng)的demo自己小練習(xí)一下,然后跟著imooc學(xué)習(xí)學(xué)習(xí),做個筆記 開...
    M_Jehol閱讀 532評論 0 0

友情鏈接更多精彩內(nèi)容