传统JavaEE集成Vue

0.简介

现在的开发都是讲究的是前后端的分离,但是有时候一些传统的老项目用的技术十分的不顺手,接下来讲一讲我是如何把Vue框架集成到老项目中去的

1.项目环境配置:

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

首先来一个整个项目的截图

传统项目的结构图

想必大家对这个结构已经十分的了解了,这里简单的介绍下这个目录的结构:

  • .settings,.classpath,.project都是Eclipse里面的配置问你件
  • adf , res ,core,metedata 是关联的其他项目的源码
  • metedata是代码生成器
  • src 是以SSH为框架的后台代码
  • WebRoot是前端代码

吐:下,这个就是老旧的JavaWeb项目,adf ,core,等都是引入的外部的的项目,这些东西是特喵的本可以打成jar包的!


2.理清楚思路:

来来来,先整理一下这个思路

在整个项目中,我们最关心的问题就是这个开发的流程怎么走,首先,明确一下开发的流程:我这里采取从前到后的方式:即由一串url说起:如 http://127.0.0.1:8080/satellite_image//index/index.jsp ,这个是指向的是index.jsp,即index.jsp是整个页面的入口,index.jsp主要的功用是分为两个部分,1是通过域对象向jsp页面里面进行传值,而作为整个页面的容器,即承载html,那么此时的html和部署在ngix上的纯前端页面就没有什么区别了,我们只需要把npm相关配置文件丢在WebRoot的根目录下即可,说白了,就是整个把整个纯前端应用限制在了WebRoot这么个文件夹下

前端需要分离的部分只能放到WebRoot下进行开发,开发的流程与传统的开发流程也没有实质性的区别:即是这样的,我们所有的jsp都要引入一个关键的*.js文件,作为整个文件的操作入口文件,然后再根据这个文件的模块,利用js模块化的思想和Vue模块化的思想将整个页面进行分隔,

先上个图:


重点关注的前端里面的东西

build文件夹是存放编译之后的js文件,css是指样式文件,images是放置图片的,js是老旧项目原始的文件,懒得管了,js-es6才是我们的重头戏,重点编写的文件,其中api是用来搞数据操作交互的和其他操作,里面封装的Data.js就是重点通过ajax与服务器端的数据进行交互的,然后还有一些地图处理的api啊之类的,components是放置的Vue组件了,啊这些就是前端需要搞的知识点儿了,啊这里的就不详细介绍了,,我们重点关注的是流程的走通对不对,

3.正文:

其实吧,最重点的还是特喵的npm那一堆配置文件


,在实际开发的时候,在npm下就跑到Webroot目录下,跑npm run dev 即可以进行热重载的开发,用npm run build-product进行最终文件的压缩,混淆之类的.

下面针对这些文件进行简单的介绍一下,先从npm的命令说起:

看一下package.json这么文件,他是整个前端项目的核心组件和文件(复制过去记得把注释去掉):

{
  "name": "mzb",  //项目的名称
  "version": "0.1.0",//版本号
  "private": true, //私有项目?
  "dependencies": { //项目中实打实需要用到的第三方插件,框架之类的,这些东西说白了,是项目的文件,或者是入口js文件需要用的,需要用的,会编译进去代码的
  "babel-runtime": "^6.26.0",//运行时,垫片库,貌似没有用到,它的作用是,配合通过babel-plugin-transform-runtime自动重写你的promise等原型对象。但是它不会模拟内置对象原型上的方法,比如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 脚本时,所能执行的命令结合,在执行脚本的时候是可以指定一些参数的,相当于cmd中进行执行命令,多个命令之间用 && 进行分隔
  "test": "echo \"Error: no test specified\" && exit 1",
  "start": "webpack",//执行webpack的命令
  "server": "webpack-dev-server --open",
  "dev": "webpack-dev-server --devtool eval-source-map --progress --colors --hot --inline ", //执行热更新开发者模式
  "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有关,待研究
  "babel-loader": "^7.1.2",//必须要有的转码器啦
  "babel-plugin-transform-runtime": "^6.23.0",//配合上述的进行工作滴
  "babel-polyfill": "^6.26.0", //用于解决低版本浏览器api不全的问题,加入之后可以为所欲为的使用高级的api,在文件的头部统一使用 import 'babel-polyfill'
  "babel-preset-es2015": "^6.24.1",//转成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-,主要是将访问方式统一抓变成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"//热更新用到的服务器啦
    }
}

详解开发模式下的webpack.config.js,即 执行npm run dev ,或者npm run build都发生了什么事情

看文件.babelre

{
"presets": [["es2015",{"loose":false}],["stage-3"]], //指定转码时,代码所需要识别的高级语法有哪些
"plugins": [     //转码插件
  "transform-runtime",//待研究
  "transform-es2015-classes"]//转es6里面的class语法,(其实吧,我觉得只用第一个就可以了,待研究)
}

看文件webpack.js

//这里用到的就是nodejs里面的内容和语法了,遵循CommonJS的规范
const path = require('path')
const webpack = require('webpack'); //使用webpack自带的插件
module.exports = {
devtool: 'eval-source-map', //调试时使用的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中的一个全局变量,它指向当前执行脚本所在的目录,故多用于构建工具的脚本中】
output: {
    path: __dirname + '/index/build', //输出的路径
    filename: 'index.js' //输出的文件名
    // publicPath: '[http://localhost:3000/](http://localhost:3000/)'
},
module: { //多个依赖模块,如babel,react,laod等模块
    rules: [ //定义loader的规则,表示如何处理指定格式的拓展文件
        {
            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下,即同一个域下,实现热加载,在执行代理时,为保证符合代理的预期效果,可以到tomcat下把需要代理的文件删掉,目前也就只能代理的是这么个入口文件
    port: 3000, //代理服务器的端口
    proxy: {
        '**': {
            target: '[http://localhost:8080](http://localhost:8080/)', //代理的 服务器地址,
            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

/*
在编译之后的脚本之后,往其头部添加一些引入的库
用途:多用于连续打包,在下一次打包之前,引入必要的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("脚本注入插件只能传入一个参数");
    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 发生了什么,重头戏,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中的一个全局变量,它指向当前执行脚本所在的目录,故多用于构建工具的脚本中】
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,根据[http://www.aliued.com/?p=3240](http://www.aliued.com/?p=3240) ,暂用得解决方案是转码再转码
     *即先webpack转码一次通用的.js文件,然后注入脚本require('es5-shim')等包,再进行另外一次webpack进行打包转码
     */
    // 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注入插件,则可以直接和下面这个文件的内容进行合并
        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,其实如不要使用注入引入的插件,则不要这样子搞,合并即可

//其实这个文件才是最后执行的,哈!

// 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中的一个全局变量,它指向当前执行脚本所在的目录,故多用于构建工具的脚本中】
output: {
    path: __dirname + '/index/build', //输出的路径
    filename: 'index.js' //输出的文件名
},
module: {
    rules: [
        {
            test: /(\.js)$/,
            use: {
                loader: 'es3ify-loader',
            }
        }
    ]
},
plugins: [
    new webpack.BannerPlugin('版权所有,翻版必究'),
    // 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){
            // 符合公司框架的解析规则
            return oldFileName.substring(0,oldFileName.indexOf("."))+".gzjs";
        },
        test: new RegExp(
            '\\.(js|css)$' //压缩 js 与 css
        ),
        threshold: 10240,
        minRatio: 0.8
    })
]
};

综上所述,以上的开发流程是这样子的

  1. 首先新建传统的javaeb项目,maven也可以啦
  2. 在WebRoot下部署node环境,即编写上述的那些个包之类的,是实际的项目发布时,是不需要/node_moudle/这个文件夹的
  3. 建立入口html或者jsp
  4. 新建入口.js,记得抽出一个文件单独处理与服务器的数据交互工作
  5. 在html中引入这个编译之后的入口文件,入口引入的方式不同,热加载的方式也不同,即webServer中,publicPath需要变一变
  6. 编写webpack的配置文件,指定入口出口文件啊,配置webserver等
  7. 在实际部署时,一定要记得跑product.config,让js文件该压缩的压缩,该混淆的混淆

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

  • 第一步:把这些npm相关的文件丢到webroot目录下

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

  • 第三步,修改webpack.config里面的入口出口参数,

  • 第四步:到WebRoot目录下:执行npm run dev,部署的时候执行npm run build-product

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,084评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,623评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,450评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,322评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,370评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,274评论 1 300
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,126评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,980评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,414评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,599评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,773评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,470评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,080评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,713评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,852评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,865评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,689评论 2 354

推荐阅读更多精彩内容

  • 写在前面 知道Vue已经有“一段”时间了,粗枝大叶的了解了点,因为当时资料比较少,正式项目中也没有开始用到,...
    我自静默向韶华阅读 473评论 2 2
  • 疑问点 之前开始学习Vue时,老是搞不清楚为什么有的时候是:v-bind:class="dynamicClass"...
    放风筝的小小马阅读 461评论 0 0
  • 代码部分请下载本文代码阅读,代码均能正常运行并有详细的注释。 本文代码下载地址 概述 前端开发近况 需求依然旺盛,...
    每一天都是开始阅读 7,627评论 3 36
  • 绑定数据 一个 Vue 的实例对应一个 element,数据通绑定的方式,在 element 中通过 {{变量名}...
    yangxg阅读 194评论 0 0
  • 据说vue最伟大的功能就是组件啦~ 我就是把官网的demo自己小练习一下,然后跟着imooc学习学习,做个笔记 开...
    M_Jehol阅读 453评论 0 0