├── src └── main │ ├── webapp │ ├── .gitkeep │ ├── favicon.ico │ ├── images │ │ ├── forie.png │ │ ├── qrcode_alipay_nq.png │ │ ├── qrcode_weibo_nnbwq.png │ │ ├── qrcode_weixin_qjzd.jpg │ │ ├── webpack.svg │ │ └── jsp.svg │ ├── WEB-INF │ │ ├── jsp │ │ │ ├── include │ │ │ │ ├── footer.jsp │ │ │ │ ├── init.jsp │ │ │ │ ├── common_script.jsp │ │ │ │ ├── meta.jsp │ │ │ │ ├── header.jsp │ │ │ │ └── lowie.jsp │ │ │ ├── contact │ │ │ │ └── index.jsp │ │ │ ├── index │ │ │ │ └── index.jsp │ │ │ └── start │ │ │ │ └── index.jsp │ │ ├── tld │ │ │ └── elfunc.tld │ │ └── web.xml │ └── static │ │ ├── fonts │ │ ├── glyphicons-halflings-regular.e18bbf6.ttf │ │ ├── glyphicons-halflings-regular.f4769f9.eot │ │ ├── glyphicons-halflings-regular.fa27723.woff │ │ └── glyphicons-halflings-regular.448c34a.woff2 │ │ └── js │ │ ├── index.f9d8e14098eb453538be.js │ │ ├── contact.ae1113387e1befd7ff8b.js │ │ ├── manifest.f93839dfcf180f0b2afc.js │ │ ├── start.d7ebb5145fef16460537.js │ │ ├── index.f9d8e14098eb453538be.js.map │ │ ├── contact.ae1113387e1befd7ff8b.js.map │ │ ├── manifest.f93839dfcf180f0b2afc.js.map │ │ └── start.d7ebb5145fef16460537.js.map │ ├── js │ ├── src │ │ ├── static │ │ │ ├── .gitkeep │ │ │ ├── favicon.ico │ │ │ ├── images │ │ │ │ ├── forie.png │ │ │ │ ├── qrcode_alipay_nq.png │ │ │ │ ├── qrcode_weibo_nnbwq.png │ │ │ │ ├── qrcode_weixin_qjzd.jpg │ │ │ │ ├── webpack.svg │ │ │ │ └── jsp.svg │ │ │ └── WEB-INF │ │ │ │ ├── tld │ │ │ │ └── elfunc.tld │ │ │ │ └── web.xml │ │ ├── shares │ │ │ └── page │ │ │ │ └── index.js │ │ ├── pages │ │ │ ├── contact │ │ │ │ ├── index.js │ │ │ │ ├── index.css │ │ │ │ └── index.jsp │ │ │ ├── index │ │ │ │ ├── index.js │ │ │ │ └── index.jsp │ │ │ ├── include │ │ │ │ ├── footer.jsp │ │ │ │ ├── init.jsp │ │ │ │ ├── common_script.jsp │ │ │ │ ├── meta.jsp │ │ │ │ ├── header.jsp │ │ │ │ └── lowie.jsp │ │ │ └── start │ │ │ │ ├── my-component.vue │ │ │ │ ├── index.js │ │ │ │ ├── dashboard.css │ │ │ │ └── index.jsp │ │ ├── polyfills │ │ │ ├── promise.js │ │ │ ├── index.js │ │ │ └── console.js │ │ └── styles │ │ │ ├── bootstrap │ │ │ └── fonts │ │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ │ ├── glyphicons-halflings-regular.woff │ │ │ │ └── glyphicons-halflings-regular.woff2 │ │ │ └── index.css │ ├── .gitignore │ ├── .eslintignore │ ├── build │ │ ├── logo.png │ │ ├── clean.js │ │ ├── vue-loader.conf.js │ │ ├── build.js │ │ ├── check-versions.js │ │ ├── webpack.dev.conf.js │ │ ├── utils.js │ │ ├── webpack.base.conf.js │ │ └── webpack.prod.conf.js │ ├── config │ │ ├── prod.env.js │ │ ├── dev.env.js │ │ ├── js-jsp-map.js │ │ └── index.js │ ├── .editorconfig │ ├── .babelrc │ ├── .postcssrc.js │ ├── .eslintrc.js │ └── package.json │ ├── resources │ ├── product │ │ ├── app.properties │ │ └── log4j.properties │ └── development │ │ ├── app.properties │ │ └── log4j.properties │ └── java │ └── net │ └── qjzd │ ├── wjsp │ ├── el │ │ └── ElUtil.java │ ├── common │ │ ├── Config.java │ │ ├── ConfigServlet.java │ │ └── StartServlet.java │ ├── config │ │ ├── BeanConfig.java │ │ ├── I18nConfig.java │ │ ├── FileUploadConfig.java │ │ ├── GlobalInterceptor.java │ │ ├── CorsFilter.java │ │ ├── ViewResolverConfig.java │ │ ├── MvcConfig.java │ │ └── WebAppConfig.java │ ├── exception │ │ ├── ErrorCode.java │ │ ├── ErrorMessage.java │ │ └── GlobalControllerAdvice.java │ └── controller │ │ └── MainController.java │ ├── base │ └── BaseController.java │ └── utils │ ├── I18nUtil.java │ ├── SpringUtil.java │ ├── ReflectUtils.java │ ├── LogUtil.java │ └── RequestUtils.java ├── .gitignore ├── README.md └── pom.xml /src/main/webapp/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/js/src/static/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/js/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /src/main/resources/product/app.properties: -------------------------------------------------------------------------------- 1 | #APP -------------------------------------------------------------------------------- /src/main/resources/development/app.properties: -------------------------------------------------------------------------------- 1 | #APP -------------------------------------------------------------------------------- /src/main/js/.eslintignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /config/ 3 | /*.js 4 | 5 | -------------------------------------------------------------------------------- /src/main/js/src/shares/page/index.js: -------------------------------------------------------------------------------- 1 | import '@/styles/index.css' 2 | -------------------------------------------------------------------------------- /src/main/js/src/pages/contact/index.js: -------------------------------------------------------------------------------- 1 | import '@/shares/page' 2 | import './index.css' 3 | -------------------------------------------------------------------------------- /src/main/js/build/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nqdy666/wjsp/HEAD/src/main/js/build/logo.png -------------------------------------------------------------------------------- /src/main/js/src/pages/index/index.js: -------------------------------------------------------------------------------- 1 | import '@/shares/page' 2 | 3 | console.log('hello world') 4 | -------------------------------------------------------------------------------- /src/main/js/src/polyfills/promise.js: -------------------------------------------------------------------------------- 1 | import Promise from 'nuo' 2 | 3 | window.Promise = Promise 4 | -------------------------------------------------------------------------------- /src/main/webapp/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nqdy666/wjsp/HEAD/src/main/webapp/favicon.ico -------------------------------------------------------------------------------- /src/main/js/config/prod.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | module.exports = { 3 | NODE_ENV: '"production"' 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/net/qjzd/wjsp/el/ElUtil.java: -------------------------------------------------------------------------------- 1 | package net.qjzd.wjsp.el; 2 | 3 | public class ElUtil { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/webapp/images/forie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nqdy666/wjsp/HEAD/src/main/webapp/images/forie.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.iml 3 | /target 4 | .settings 5 | .project 6 | .classpath 7 | .externalToolBuilders 8 | /classes -------------------------------------------------------------------------------- /src/main/js/src/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nqdy666/wjsp/HEAD/src/main/js/src/static/favicon.ico -------------------------------------------------------------------------------- /src/main/js/src/static/images/forie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nqdy666/wjsp/HEAD/src/main/js/src/static/images/forie.png -------------------------------------------------------------------------------- /src/main/js/src/pages/include/footer.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 | 3 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/jsp/include/footer.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 | 3 | -------------------------------------------------------------------------------- /src/main/webapp/images/qrcode_alipay_nq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nqdy666/wjsp/HEAD/src/main/webapp/images/qrcode_alipay_nq.png -------------------------------------------------------------------------------- /src/main/webapp/images/qrcode_weibo_nnbwq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nqdy666/wjsp/HEAD/src/main/webapp/images/qrcode_weibo_nnbwq.png -------------------------------------------------------------------------------- /src/main/webapp/images/qrcode_weixin_qjzd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nqdy666/wjsp/HEAD/src/main/webapp/images/qrcode_weixin_qjzd.jpg -------------------------------------------------------------------------------- /src/main/js/src/static/images/qrcode_alipay_nq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nqdy666/wjsp/HEAD/src/main/js/src/static/images/qrcode_alipay_nq.png -------------------------------------------------------------------------------- /src/main/js/src/static/images/qrcode_weibo_nnbwq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nqdy666/wjsp/HEAD/src/main/js/src/static/images/qrcode_weibo_nnbwq.png -------------------------------------------------------------------------------- /src/main/js/src/static/images/qrcode_weixin_qjzd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nqdy666/wjsp/HEAD/src/main/js/src/static/images/qrcode_weixin_qjzd.jpg -------------------------------------------------------------------------------- /src/main/webapp/static/fonts/glyphicons-halflings-regular.e18bbf6.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nqdy666/wjsp/HEAD/src/main/webapp/static/fonts/glyphicons-halflings-regular.e18bbf6.ttf -------------------------------------------------------------------------------- /src/main/webapp/static/fonts/glyphicons-halflings-regular.f4769f9.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nqdy666/wjsp/HEAD/src/main/webapp/static/fonts/glyphicons-halflings-regular.f4769f9.eot -------------------------------------------------------------------------------- /src/main/webapp/static/fonts/glyphicons-halflings-regular.fa27723.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nqdy666/wjsp/HEAD/src/main/webapp/static/fonts/glyphicons-halflings-regular.fa27723.woff -------------------------------------------------------------------------------- /src/main/js/src/styles/bootstrap/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nqdy666/wjsp/HEAD/src/main/js/src/styles/bootstrap/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /src/main/js/src/styles/bootstrap/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nqdy666/wjsp/HEAD/src/main/js/src/styles/bootstrap/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /src/main/js/src/styles/bootstrap/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nqdy666/wjsp/HEAD/src/main/js/src/styles/bootstrap/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /src/main/webapp/static/fonts/glyphicons-halflings-regular.448c34a.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nqdy666/wjsp/HEAD/src/main/webapp/static/fonts/glyphicons-halflings-regular.448c34a.woff2 -------------------------------------------------------------------------------- /src/main/java/net/qjzd/wjsp/common/Config.java: -------------------------------------------------------------------------------- 1 | package net.qjzd.wjsp.common; 2 | 3 | public class Config { 4 | public static final String WEB_ACCEPT = "Accept=application/json"; 5 | } 6 | -------------------------------------------------------------------------------- /src/main/js/src/styles/bootstrap/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nqdy666/wjsp/HEAD/src/main/js/src/styles/bootstrap/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /src/main/js/config/dev.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const merge = require('webpack-merge') 3 | const prodEnv = require('./prod.env') 4 | 5 | module.exports = merge(prodEnv, { 6 | NODE_ENV: '"development"' 7 | }) 8 | -------------------------------------------------------------------------------- /src/main/js/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /src/main/js/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "modules": false 5 | }], 6 | "stage-2" 7 | ], 8 | "plugins": ["transform-runtime"], 9 | "env": { 10 | "test": { 11 | "presets": ["env", "stage-2"] } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/js/.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | // to edit target browsers: use "browserslist" field in package.json 6 | "postcss-import": {}, 7 | "postcss-url": {}, 8 | 'postcss-nested': {}, 9 | "autoprefixer": {} 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/js/build/clean.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const ora = require('ora') 4 | const rm = require('rimraf') 5 | const path = require('path') 6 | const config = require('../config') 7 | 8 | const spinner = ora('cleaning...') 9 | spinner.start() 10 | 11 | rm(path.join(config.build.assetsRoot), err => { 12 | if (err) throw err 13 | }) 14 | -------------------------------------------------------------------------------- /src/main/java/net/qjzd/wjsp/config/BeanConfig.java: -------------------------------------------------------------------------------- 1 | package net.qjzd.wjsp.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.context.annotation.PropertySource; 5 | 6 | @Configuration 7 | @PropertySource(value = {"classpath:app.properties"}) 8 | public class BeanConfig { 9 | } 10 | -------------------------------------------------------------------------------- /src/main/js/src/pages/contact/index.css: -------------------------------------------------------------------------------- 1 | .contact-main { 2 | margin-top: 100px; 3 | margin-bottom: 10px; 4 | 5 | .placeholder { 6 | h4 { 7 | text-align: center; 8 | } 9 | .text-muted { 10 | display: block; 11 | text-align: center; 12 | } 13 | } 14 | } 15 | 16 | @media (max-width: 700px) { 17 | .contact-main { 18 | margin-top: 10px; 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /src/main/js/src/pages/start/my-component.vue: -------------------------------------------------------------------------------- 1 | 10 | 19 | -------------------------------------------------------------------------------- /src/main/java/net/qjzd/wjsp/common/ConfigServlet.java: -------------------------------------------------------------------------------- 1 | package net.qjzd.wjsp.common; 2 | 3 | import javax.servlet.ServletException; 4 | import javax.servlet.http.HttpServlet; 5 | 6 | public class ConfigServlet extends HttpServlet { 7 | 8 | private static final long serialVersionUID = 6794852229635296067L; 9 | 10 | @Override 11 | public void init() throws ServletException { 12 | // TODO Auto-generated method stub 13 | super.init(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/js/src/polyfills/index.js: -------------------------------------------------------------------------------- 1 | import './promise' 2 | import './console' 3 | import 'core-js/es6/array' 4 | import 'core-js/fn/array/of' 5 | import 'core-js/fn/array/find' 6 | import 'core-js/fn/array/find-index' 7 | import 'core-js/fn/object/assign' 8 | import 'core-js/fn/array/includes' 9 | import 'core-js/fn/array/iterator' 10 | import 'core-js/es6/string' 11 | import 'core-js/es6/map' 12 | import 'core-js/es6/symbol' 13 | import 'regenerator-runtime/runtime' 14 | import 'whatwg-fetch' 15 | -------------------------------------------------------------------------------- /src/main/js/src/pages/include/init.jsp: -------------------------------------------------------------------------------- 1 | <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8" pageEncoding="utf-8" isELIgnored="false" %> 2 | <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> 3 | <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> 4 | <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> 5 | <%@ taglib prefix="elf" uri="/WEB-INF/tld/elfunc.tld" %> 6 | 7 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/jsp/include/init.jsp: -------------------------------------------------------------------------------- 1 | <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8" pageEncoding="utf-8" isELIgnored="false" %> 2 | <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> 3 | <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> 4 | <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> 5 | <%@ taglib prefix="elf" uri="/WEB-INF/tld/elfunc.tld" %> 6 | 7 | -------------------------------------------------------------------------------- /src/main/js/src/pages/include/common_script.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 | 3 | 4 | 13 | -------------------------------------------------------------------------------- /src/main/js/src/pages/include/meta.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/jsp/include/common_script.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 | 3 | 4 | 13 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/jsp/include/meta.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/main/java/net/qjzd/wjsp/common/StartServlet.java: -------------------------------------------------------------------------------- 1 | package net.qjzd.wjsp.common; 2 | 3 | import net.qjzd.utils.SpringUtil; 4 | 5 | import javax.servlet.ServletException; 6 | import javax.servlet.http.HttpServlet; 7 | 8 | public class StartServlet extends HttpServlet { 9 | 10 | private static final long serialVersionUID = -6562937892680056788L; 11 | 12 | @Override 13 | public void init() throws ServletException { 14 | // TODO Auto-generated method stub 15 | SpringUtil.getInstance(this.getServletContext()); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/js/build/vue-loader.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const config = require('../config') 4 | const isProduction = process.env.NODE_ENV === 'production' 5 | const sourceMapEnabled = isProduction 6 | ? config.build.productionSourceMap 7 | : config.dev.cssSourceMap 8 | 9 | 10 | module.exports = { 11 | loaders: utils.cssLoaders({ 12 | sourceMap: sourceMapEnabled, 13 | extract: isProduction 14 | }), 15 | cssSourceMap: sourceMapEnabled, 16 | transformToRequire: { 17 | video: 'src', 18 | source: 'src', 19 | img: 'src', 20 | image: 'xlink:href' 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/js/src/polyfills/console.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | var method 3 | var noop = function () {} 4 | var methods = [ 5 | 'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error', 6 | 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', 7 | 'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd', 8 | 'timeStamp', 'trace', 'warn' 9 | ] 10 | var length = methods.length 11 | var console = (window.console = window.console || {}) 12 | 13 | while (length--) { 14 | method = methods[length] 15 | 16 | // Only stub undefined methods. 17 | if (!console[method]) { 18 | console[method] = noop 19 | } 20 | } 21 | }()) 22 | -------------------------------------------------------------------------------- /src/main/webapp/images/webpack.svg: -------------------------------------------------------------------------------- 1 | icon-square-big 2 | -------------------------------------------------------------------------------- /src/main/js/src/static/images/webpack.svg: -------------------------------------------------------------------------------- 1 | icon-square-big 2 | -------------------------------------------------------------------------------- /src/main/js/config/js-jsp-map.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('../build/utils') 3 | 4 | const pathResolve = utils.pathResolve 5 | 6 | function jsPathResolve(path) { 7 | return pathResolve.src('pages', path) 8 | } 9 | 10 | function jspPathResolve(path) { 11 | return pathResolve.dist('WEB-INF/jsp', path) 12 | } 13 | 14 | const jsJspMap = [ 15 | { name: 'index', jsPath: jsPathResolve('index/index.js'), jspPath: jspPathResolve('index/index.jsp') }, 16 | { name: 'start', jsPath: jsPathResolve('start/index.js'), jspPath: jspPathResolve('start/index.jsp') }, 17 | { name: 'contact', jsPath: jsPathResolve('contact/index.js'), jspPath: jspPathResolve('contact/index.jsp') } 18 | ] 19 | 20 | module.exports = jsJspMap 21 | -------------------------------------------------------------------------------- /src/main/java/net/qjzd/base/BaseController.java: -------------------------------------------------------------------------------- 1 | package net.qjzd.base; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.web.servlet.ModelAndView; 6 | import org.springframework.web.servlet.mvc.Controller; 7 | 8 | import javax.servlet.http.HttpServletRequest; 9 | import javax.servlet.http.HttpServletResponse; 10 | 11 | /** 12 | * Created by NQLDY on 2017/6/10. 13 | */ 14 | public class BaseController implements Controller { 15 | 16 | protected Logger logger = LoggerFactory.getLogger(BaseController.class); 17 | 18 | @Override 19 | public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { 20 | return null; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/net/qjzd/wjsp/config/I18nConfig.java: -------------------------------------------------------------------------------- 1 | package net.qjzd.wjsp.config; 2 | 3 | import org.apache.log4j.Logger; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.context.support.ResourceBundleMessageSource; 7 | 8 | @Configuration 9 | public class I18nConfig { 10 | private static final Logger logger = Logger.getLogger(I18nConfig.class); 11 | 12 | @Bean 13 | public ResourceBundleMessageSource messageSource() { 14 | ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); 15 | messageSource.setBasename("i18n"); 16 | messageSource.setUseCodeAsDefaultMessage(true); 17 | messageSource.setDefaultEncoding("UTF-8"); 18 | return messageSource; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/js/.eslintrc.js: -------------------------------------------------------------------------------- 1 | // https://eslint.org/docs/user-guide/configuring 2 | 3 | module.exports = { 4 | root: true, 5 | parser: 'babel-eslint', 6 | parserOptions: { 7 | sourceType: 'module' 8 | }, 9 | env: { 10 | browser: true, 11 | }, 12 | // https://github.com/standard/standard/blob/master/docs/RULES-en.md 13 | extends: 'standard', 14 | globals: { 15 | '$': false 16 | }, 17 | // required to lint *.vue files 18 | plugins: [ 19 | 'html' 20 | ], 21 | // add your custom rules here 22 | 'rules': { 23 | // allow paren-less arrow functions 24 | 'arrow-parens': 0, 25 | // allow async-await 26 | 'generator-star-spacing': 0, 27 | // allow debugger during development 28 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, 29 | "no-new": 0 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/net/qjzd/utils/I18nUtil.java: -------------------------------------------------------------------------------- 1 | package net.qjzd.utils; 2 | 3 | import org.springframework.web.servlet.support.RequestContext; 4 | 5 | /** 6 | *

Title: I18nUtil

7 | *

Description: 国际化转换message

8 | *

Copyright: Copyright (c) 2015

9 | *

Company: ND Websoft Inc.

10 | *

Create Time: 2017年06月16日

11 | * @author lianggz 12 | */ 13 | public class I18nUtil { 14 | 15 | public static String getMessage(String key) { 16 | RequestContext requestContext = new RequestContext(SpringUtil.getRequest()); 17 | return requestContext.getMessage(key); 18 | } 19 | 20 | public static String getMessage(String key, Object... objects) { 21 | RequestContext requestContext = new RequestContext(SpringUtil.getRequest()); 22 | return requestContext.getMessage(key, objects); 23 | } 24 | } -------------------------------------------------------------------------------- /src/main/java/net/qjzd/wjsp/exception/ErrorCode.java: -------------------------------------------------------------------------------- 1 | package net.qjzd.wjsp.exception; 2 | 3 | /** 4 | *

Title: ErrorCode

5 | *

Description: 错误码枚举

6 | *

Copyright: Copyright (c) 2015

7 | *

Company: ND Websoft Inc.

8 | *

Create Time: 2015年07月14日

9 | * @author lianggz 10 | */ 11 | public enum ErrorCode { 12 | //无效请求 13 | URI_NOT_FOUND(400, "URI_NOT_FOUND"), 14 | //服务器错误 15 | INTERNAL_SERVER_ERROR(500, "INTERNAL_SERVER_ERROR"), 16 | ; 17 | protected String PROVIDER = "WJSP/"; 18 | 19 | private final int value; 20 | private final String code; 21 | 22 | ErrorCode(int value, String code) { 23 | this.value = value; 24 | this.code = code; 25 | } 26 | 27 | public int getValue() { 28 | return this.value; 29 | } 30 | 31 | public String getCode() { 32 | return this.PROVIDER + this.code; 33 | } 34 | } -------------------------------------------------------------------------------- /src/main/webapp/static/js/index.f9d8e14098eb453538be.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([3],{0:function(e,o,n){n("cZNe"),e.exports=n("U67u")},"Pp/C":function(e,o){!function(){for(var e,o=function(){},n=["assert","clear","count","debug","dir","dirxml","error","exception","group","groupCollapsed","groupEnd","info","log","markTimeline","profile","profileEnd","table","time","timeEnd","timeStamp","trace","warn"],i=n.length,r=window.console=window.console||{};i--;)e=n[i],r[e]||(r[e]=o)}()},U67u:function(e,o,n){"use strict";Object.defineProperty(o,"__esModule",{value:!0});n("i5Z1");console.log("hello world")},cZNe:function(e,o,n){"use strict";Object.defineProperty(o,"__esModule",{value:!0});var i=n("SbJX"),r=n.n(i);window.Promise=r.a;n("Pp/C"),n("cUYv"),n("PPkL"),n("0K64"),n("X8hh"),n("kLF+"),n("fB7P"),n("mBqO"),n("oFcf"),n("7N90"),n("wu3h"),n("SldL"),n("rplX")},h2zT:function(e,o){},i5Z1:function(e,o,n){"use strict";var i=n("h2zT");n.n(i)}},[0]); 2 | //# sourceMappingURL=index.f9d8e14098eb453538be.js.map -------------------------------------------------------------------------------- /src/main/java/net/qjzd/wjsp/config/FileUploadConfig.java: -------------------------------------------------------------------------------- 1 | package net.qjzd.wjsp.config; 2 | 3 | import org.apache.log4j.Logger; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.web.multipart.commons.CommonsMultipartResolver; 7 | 8 | @Configuration 9 | public class FileUploadConfig { 10 | private static final Logger logger = Logger.getLogger(FileUploadConfig.class); 11 | 12 | private static final String DEFAULT_ENCODING = "UTF-8"; 13 | private static final Integer MAX_UPLOAD_SIZE = 2 * 1024 * 1024; 14 | 15 | @Bean 16 | public CommonsMultipartResolver multipartResolver() { 17 | CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver(); 18 | commonsMultipartResolver.setDefaultEncoding(DEFAULT_ENCODING); 19 | commonsMultipartResolver.setMaxUploadSize(MAX_UPLOAD_SIZE); 20 | return commonsMultipartResolver; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/webapp/static/js/contact.ae1113387e1befd7ff8b.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([2],{2:function(e,n,o){o("cZNe"),e.exports=o("CNGw")},CNGw:function(e,n,o){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var r=(o("i5Z1"),o("rv4b"));o.n(r)},"Pp/C":function(e,n){!function(){for(var e,n=function(){},o=["assert","clear","count","debug","dir","dirxml","error","exception","group","groupCollapsed","groupEnd","info","log","markTimeline","profile","profileEnd","table","time","timeEnd","timeStamp","trace","warn"],r=o.length,i=window.console=window.console||{};r--;)e=o[r],i[e]||(i[e]=n)}()},cZNe:function(e,n,o){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var r=o("SbJX"),i=o.n(r);window.Promise=i.a;o("Pp/C"),o("cUYv"),o("PPkL"),o("0K64"),o("X8hh"),o("kLF+"),o("fB7P"),o("mBqO"),o("oFcf"),o("7N90"),o("wu3h"),o("SldL"),o("rplX")},h2zT:function(e,n){},i5Z1:function(e,n,o){"use strict";var r=o("h2zT");o.n(r)},rv4b:function(e,n){}},[2]); 2 | //# sourceMappingURL=contact.ae1113387e1befd7ff8b.js.map -------------------------------------------------------------------------------- /src/main/js/src/pages/include/header.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 | 23 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/jsp/include/header.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 | 23 | -------------------------------------------------------------------------------- /src/main/java/net/qjzd/utils/SpringUtil.java: -------------------------------------------------------------------------------- 1 | package net.qjzd.utils; 2 | 3 | import org.springframework.web.context.WebApplicationContext; 4 | import org.springframework.web.context.request.RequestContextHolder; 5 | import org.springframework.web.context.request.ServletRequestAttributes; 6 | 7 | import javax.servlet.ServletContext; 8 | import javax.servlet.http.HttpServletRequest; 9 | 10 | /** 11 | * spring工具 12 | * 13 | * @author nianqin 14 | */ 15 | public class SpringUtil { 16 | 17 | public static WebApplicationContext context = null; 18 | 19 | public static void getInstance(ServletContext sc) { 20 | context = (WebApplicationContext) sc 21 | .getAttribute("org.springframework.web.servlet.FrameworkServlet.CONTEXT.springWebDispatcherServlet"); 22 | } 23 | 24 | public static Object getBean(String beanName) { 25 | if (context == null) { 26 | return null; 27 | } 28 | return context.getBean(beanName); 29 | } 30 | 31 | public static HttpServletRequest getRequest() { 32 | return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/resources/product/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootLogger=debug,console,logfile 2 | # Console 3 | log4j.appender.console=org.apache.log4j.ConsoleAppender 4 | log4j.appender.console.Threshold=debug 5 | log4j.appender.console.Target=System.out 6 | log4j.appender.console.layout=org.apache.log4j.PatternLayout 7 | log4j.appender.console.layout.ConversionPattern=[%p][%d{yyyy-MM-dd HH\:mm\:ss\:SSS}][%c] %m%n 8 | 9 | # File (day a file) 10 | log4j.appender.logfile=org.apache.log4j.DailyRollingFileAppender 11 | log4j.appender.logfile.Threshold=debug 12 | log4j.appender.logfile.File=${catalina.home}/logs/log.log 13 | log4j.appender.logfile.DatePattern = '.'yyyy-MM-dd 14 | log4j.appender.logfile.layout=org.apache.log4j.PatternLayout 15 | #[%p][%d{yyyy-MM-dd HH\:mm\:ss\:SSS}][%F] %m%n 16 | log4j.appender.logfile.layout.ConversionPattern=[%p][%d{yyyy-MM-dd HH\:mm\:ss\:SSS}][%c] %m%n 17 | 18 | log4j.logger.org.apache.axis.ConfigurationException=INFO 19 | log4j.logger.com.mchange.v2=ERROR 20 | log4j.logger.org.springframework=INFO 21 | log4j.logger.org.apache.commons=ERROR 22 | log4j.logger.httpclient.wire.content=ERROR 23 | log4j.logger.httpclient.wire.header=ERROR 24 | -------------------------------------------------------------------------------- /src/main/resources/development/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootLogger=debug,console,logfile 2 | # Console 3 | log4j.appender.console=org.apache.log4j.ConsoleAppender 4 | log4j.appender.console.Threshold=debug 5 | log4j.appender.console.Target=System.out 6 | log4j.appender.console.layout=org.apache.log4j.PatternLayout 7 | log4j.appender.console.layout.ConversionPattern=[%p][%d{yyyy-MM-dd HH\:mm\:ss\:SSS}][%c] %m%n 8 | 9 | # File (day a file) 10 | log4j.appender.logfile=org.apache.log4j.DailyRollingFileAppender 11 | log4j.appender.logfile.Threshold=debug 12 | log4j.appender.logfile.File=${catalina.home}/logs/log.log 13 | log4j.appender.logfile.DatePattern = '.'yyyy-MM-dd 14 | log4j.appender.logfile.layout=org.apache.log4j.PatternLayout 15 | #[%p][%d{yyyy-MM-dd HH\:mm\:ss\:SSS}][%F] %m%n 16 | log4j.appender.logfile.layout.ConversionPattern=[%p][%d{yyyy-MM-dd HH\:mm\:ss\:SSS}][%c] %m%n 17 | 18 | log4j.logger.org.apache.axis.ConfigurationException=INFO 19 | log4j.logger.com.mchange.v2=ERROR 20 | log4j.logger.org.springframework=INFO 21 | log4j.logger.org.apache.commons=ERROR 22 | log4j.logger.httpclient.wire.content=ERROR 23 | log4j.logger.httpclient.wire.header=ERROR 24 | -------------------------------------------------------------------------------- /src/main/java/net/qjzd/wjsp/config/GlobalInterceptor.java: -------------------------------------------------------------------------------- 1 | package net.qjzd.wjsp.config; 2 | 3 | import lombok.extern.apachecommons.CommonsLog; 4 | import org.springframework.stereotype.Component; 5 | import org.springframework.web.servlet.HandlerInterceptor; 6 | import org.springframework.web.servlet.ModelAndView; 7 | 8 | import javax.servlet.http.HttpServletRequest; 9 | import javax.servlet.http.HttpServletResponse; 10 | 11 | @Component 12 | public class GlobalInterceptor implements HandlerInterceptor { 13 | 14 | @Override 15 | public boolean preHandle(HttpServletRequest request, HttpServletResponse arg1, 16 | Object arg2) throws Exception { 17 | // TODO Auto-generated method stub 18 | return true; 19 | } 20 | 21 | @Override 22 | public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, 23 | Object arg2, ModelAndView arg3) throws Exception { 24 | // TODO Auto-generated method stub 25 | } 26 | 27 | @Override 28 | public void afterCompletion(HttpServletRequest arg0, 29 | HttpServletResponse arg1, Object arg2, Exception arg3) 30 | throws Exception { 31 | // TODO Auto-generated method stub 32 | 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/net/qjzd/wjsp/controller/MainController.java: -------------------------------------------------------------------------------- 1 | package net.qjzd.wjsp.controller; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.RequestMethod; 7 | 8 | @Controller 9 | @RequestMapping("") 10 | public class MainController { 11 | 12 | @Autowired 13 | @RequestMapping(value="/", method=RequestMethod.GET) 14 | public String index() throws Exception { 15 | return "index/index"; 16 | } 17 | 18 | @RequestMapping(value="/start", method=RequestMethod.GET) 19 | public String start() throws Exception { 20 | return "start/index"; 21 | } 22 | 23 | @RequestMapping(value="/contact", method=RequestMethod.GET) 24 | public String contact() throws Exception { 25 | return "contact/index"; 26 | } 27 | 28 | @RequestMapping(value="/404", method=RequestMethod.GET) 29 | public String notFound() throws Exception { 30 | return "index/index"; 31 | } 32 | 33 | @RequestMapping(value="/error", method=RequestMethod.GET) 34 | public String error() throws Exception { 35 | return "index/index"; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/js/src/pages/start/index.js: -------------------------------------------------------------------------------- 1 | import '@/shares/page' 2 | import './dashboard.css' 3 | import $ from 'jquery' 4 | import Vue from 'vue' 5 | import myComponent from './my-component' 6 | 7 | // Smooth scrolling using jQuery easing 8 | $('a.js-scroll-trigger[href*="#"]:not([href="#"])').click(function () { 9 | console.log(location.pathname, this.pathname) 10 | if (location.pathname.replace(/^\//, '') === this.pathname.replace(/^\//, '') && location.hostname === this.hostname) { 11 | console.log(this.hash) 12 | var target = $(this.hash) 13 | target = target.length ? target : $('[name=' + this.hash.slice(1) + ']') 14 | if (target.length) { 15 | $('html, body').animate({ 16 | scrollTop: (target.offset().top - 60) 17 | }, 300) 18 | return false 19 | } 20 | } 21 | }) 22 | 23 | // Closes responsive menu when a scroll trigger link is clicked 24 | $('.js-scroll-trigger').click(function () { 25 | $('.navbar-collapse').collapse('hide') 26 | }) 27 | 28 | // Activate scrollspy to add active class to navbar items on scroll 29 | $('body').scrollspy({ 30 | target: '#sideNav', 31 | offset: 80 32 | }) 33 | 34 | new Vue({ 35 | el: '#vue-app', 36 | components: { 37 | myComponent 38 | } 39 | }) 40 | -------------------------------------------------------------------------------- /src/main/js/build/build.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | require('./check-versions')() 3 | 4 | process.env.NODE_ENV = 'production' 5 | 6 | const ora = require('ora') 7 | const rm = require('rimraf') 8 | const path = require('path') 9 | const chalk = require('chalk') 10 | const webpack = require('webpack') 11 | const config = require('../config') 12 | const webpackConfig = require('./webpack.prod.conf') 13 | 14 | const spinner = ora('building for production...') 15 | spinner.start() 16 | 17 | rm(path.join(config.build.assetsRoot), err => { 18 | if (err) throw err 19 | webpack(webpackConfig, function (err, stats) { 20 | spinner.stop() 21 | if (err) throw err 22 | process.stdout.write(stats.toString({ 23 | colors: true, 24 | modules: false, 25 | children: false, 26 | chunks: false, 27 | chunkModules: false 28 | }) + '\n\n') 29 | 30 | if (stats.hasErrors()) { 31 | console.log(chalk.red(' Build failed with errors.\n')) 32 | process.exit(1) 33 | } 34 | 35 | console.log(chalk.cyan(' Build complete.\n')) 36 | console.log(chalk.yellow( 37 | ' Tip: built files are meant to be served over an HTTP server.\n' + 38 | ' Opening index.html over file:// won\'t work.\n' 39 | )) 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /src/main/js/src/pages/include/lowie.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 | 44 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/jsp/include/lowie.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 | 44 | -------------------------------------------------------------------------------- /src/main/java/net/qjzd/wjsp/exception/ErrorMessage.java: -------------------------------------------------------------------------------- 1 | package net.qjzd.wjsp.exception; 2 | 3 | 4 | import java.io.Serializable; 5 | 6 | /** 7 | * 错误信息封装类 8 | */ 9 | public class ErrorMessage implements Serializable { 10 | private static final long serialVersionUID = -5401402542472113075L; 11 | 12 | private String code; 13 | private String message; 14 | private String detail; 15 | 16 | public ErrorMessage() { 17 | } 18 | 19 | public ErrorMessage(String code) { 20 | this(code, "", ""); 21 | } 22 | 23 | public ErrorMessage(String code, String message) { 24 | this(code, message, ""); 25 | } 26 | 27 | public ErrorMessage(String code, String message, String detail) { 28 | this.message = message; 29 | this.code = code; 30 | this.detail = detail; 31 | } 32 | 33 | 34 | public String getCode() { 35 | return code; 36 | } 37 | 38 | public void setCode(String code) { 39 | this.code = code; 40 | } 41 | 42 | public String getMessage() { 43 | return message; 44 | } 45 | 46 | public void setMessage(String message) { 47 | this.message = message; 48 | } 49 | 50 | public String getDetail() { 51 | return detail; 52 | } 53 | 54 | public void setDetail(String detail) { 55 | this.detail = detail; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/js/build/check-versions.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const chalk = require('chalk') 3 | const semver = require('semver') 4 | const packageConfig = require('../package.json') 5 | const shell = require('shelljs') 6 | function exec (cmd) { 7 | return require('child_process').execSync(cmd).toString().trim() 8 | } 9 | 10 | const versionRequirements = [ 11 | { 12 | name: 'node', 13 | currentVersion: semver.clean(process.version), 14 | versionRequirement: packageConfig.engines.node 15 | } 16 | ] 17 | 18 | if (shell.which('npm')) { 19 | versionRequirements.push({ 20 | name: 'npm', 21 | currentVersion: exec('npm --version'), 22 | versionRequirement: packageConfig.engines.npm 23 | }) 24 | } 25 | 26 | module.exports = function () { 27 | const warnings = [] 28 | for (let i = 0; i < versionRequirements.length; i++) { 29 | const mod = versionRequirements[i] 30 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 31 | warnings.push(mod.name + ': ' + 32 | chalk.red(mod.currentVersion) + ' should be ' + 33 | chalk.green(mod.versionRequirement) 34 | ) 35 | } 36 | } 37 | 38 | if (warnings.length) { 39 | console.log('') 40 | console.log(chalk.yellow('To use this template, you must update following to modules:')) 41 | console.log() 42 | for (let i = 0; i < warnings.length; i++) { 43 | const warning = warnings[i] 44 | console.log(' ' + warning) 45 | } 46 | console.log() 47 | process.exit(1) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/webapp/static/js/manifest.f93839dfcf180f0b2afc.js: -------------------------------------------------------------------------------- 1 | !function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var r=window.webpackJsonp;window.webpackJsonp=function(t,c,a){for(var u,i,f,s=0,l=[];sTitle:

9 | *

Description:

10 | *

Copyright: Copyright (c) 2016

11 | *

Company:ND Co., Ltd.

12 | *

Create Time: 2017/6/19

13 | * 14 | * @author nianqin 15 | */ 16 | public class CorsFilter implements Filter { 17 | 18 | @Override 19 | public void init(FilterConfig filterConfig) throws ServletException { 20 | } 21 | 22 | @Override 23 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 24 | HttpServletResponse servletResponse = (HttpServletResponse) response; 25 | servletResponse.setHeader("Access-Control-Allow-Origin", "*"); 26 | servletResponse.setHeader("Access-Control-Allow-Methods", "GET, POST, HEAD, OPTIONS, PUT, DELETE, TRACE, PATCH"); 27 | servletResponse.setHeader("Access-Control-Max-Age", "3600"); 28 | // Authorization是做了oauth2登录响应所必须的 29 | servletResponse.setHeader("Access-Control-Allow-Headers", "Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers, Authorization, Cache-control, Orgname"); 30 | // 表示允许cookies 31 | servletResponse.setHeader("Access-Control-Allow-Credentials","true"); 32 | chain.doFilter(request, servletResponse); 33 | } 34 | 35 | @Override 36 | public void destroy() { 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/js/src/pages/contact/index.jsp: -------------------------------------------------------------------------------- 1 | <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" isELIgnored="false" %> 2 | <%@include file="../include/init.jsp"%> 3 | 4 | 5 | 6 | WEBPACK-JSP 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |
18 | Generic placeholder thumbnail 19 |

新浪微博-念念不忘秦

20 | 欢迎关注 21 |
22 |
23 | Generic placeholder thumbnail 24 |

微信公众号-秦晋之巅

25 | 欢迎关注 26 |
27 |
28 | Generic placeholder thumbnail 29 |

支付宝-付款码

30 | 如果觉得这对您有帮助可以请我喝一杯咖啡 31 |
32 |
33 |
34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/tld/elfunc.tld: -------------------------------------------------------------------------------- 1 | 2 | 5 | 1.0 6 | elf 7 | 8 | 字节数转成人可以读的形式,代码G,M,KB后缀 9 | byteCountToDisplaySize 10 | com.nd.ppt101.utils.ElFuncUtil 11 | 12 | java.lang.String byteCountToDisplaySize(java.lang.Long) 13 | ${elf:byteCountToDisplaySize(size)} 14 | 15 | 16 | 17 | 从map中获取第一个值,并转成string类型 18 | getFirstValueFromMap 19 | com.nd.ppt101.utils.ElFuncUtil 20 | 21 | java.lang.String getFirstValueFromMap(java.util.Map) 22 | ${elf:getFirstValueFromMap(map)} 23 | 24 | 25 | 26 | java正则表达式去除html标签 27 | htmlRemoveTag 28 | com.nd.ppt101.utils.ElFuncUtil 29 | 30 | java.lang.String htmlRemoveTag(java.lang.String) 31 | ${elf:htmlRemoveTag(htmlStr)} 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/main/js/src/static/WEB-INF/tld/elfunc.tld: -------------------------------------------------------------------------------- 1 | 2 | 5 | 1.0 6 | elf 7 | 8 | 字节数转成人可以读的形式,代码G,M,KB后缀 9 | byteCountToDisplaySize 10 | com.nd.ppt101.utils.ElFuncUtil 11 | 12 | java.lang.String byteCountToDisplaySize(java.lang.Long) 13 | ${elf:byteCountToDisplaySize(size)} 14 | 15 | 16 | 17 | 从map中获取第一个值,并转成string类型 18 | getFirstValueFromMap 19 | com.nd.ppt101.utils.ElFuncUtil 20 | 21 | java.lang.String getFirstValueFromMap(java.util.Map) 22 | ${elf:getFirstValueFromMap(map)} 23 | 24 | 25 | 26 | java正则表达式去除html标签 27 | htmlRemoveTag 28 | com.nd.ppt101.utils.ElFuncUtil 29 | 30 | java.lang.String htmlRemoveTag(java.lang.String) 31 | ${elf:htmlRemoveTag(htmlStr)} 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/main/js/src/pages/index/index.jsp: -------------------------------------------------------------------------------- 1 | <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" isELIgnored="false" %> 2 | <%@include file="../include/init.jsp"%> 3 | 4 | 5 | 6 | WEBPACK-JSP 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 | 19 | 20 |

WEBPACK + JSP 构建多页应用

21 |

传统的JSP页面应用无法有效的使用ES6语法特性,项目打包压缩困难,无法热更新。传统的单页应用在Tomcat等容器下无法进行服务端渲染从而达到SEO的效果。本项目工程很好融合的传统JSP页面服务端渲染的特点和单页应用开发特性且极易上手使用!

22 |

开始使用 23 |

24 |
25 |
26 | 27 |
28 | 29 |
30 |
31 |

WEBPACK

32 |

语法转换,打包,压缩,热更新

33 |
34 |
35 |

JSP

36 |

热部署,服务端渲染SEO

37 |
38 |
39 |

鱼与熊掌兼得

40 |

吸收WEBPACK和JSP优点,使用简单

41 |
42 |
43 |
44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/main/java/net/qjzd/wjsp/config/ViewResolverConfig.java: -------------------------------------------------------------------------------- 1 | package net.qjzd.wjsp.config; 2 | 3 | import org.apache.log4j.Logger; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.web.servlet.View; 7 | import org.springframework.web.servlet.view.ContentNegotiatingViewResolver; 8 | import org.springframework.web.servlet.view.InternalResourceViewResolver; 9 | import org.springframework.web.servlet.view.json.MappingJackson2JsonView; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | @Configuration 15 | public class ViewResolverConfig { 16 | private static final Logger logger = Logger.getLogger(ViewResolverConfig.class); 17 | 18 | private static final String VIEW_RESOLVER_PREFIX = "/WEB-INF/jsp/"; 19 | private static final String VIEW_RESOLVER_SUFFIX = ".jsp"; 20 | 21 | @Bean 22 | public ContentNegotiatingViewResolver contentNegotiatingViewResolver() { 23 | ContentNegotiatingViewResolver contentNegotiatingViewResolver = new ContentNegotiatingViewResolver(); 24 | contentNegotiatingViewResolver.setOrder(1); 25 | List listView = new ArrayList<>(); 26 | listView.add(new MappingJackson2JsonView()); 27 | contentNegotiatingViewResolver.setDefaultViews(listView); 28 | return contentNegotiatingViewResolver; 29 | } 30 | 31 | @Bean 32 | public InternalResourceViewResolver internalResourceViewResolver() { 33 | InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); 34 | viewResolver.setOrder(2); 35 | viewResolver.setPrefix(VIEW_RESOLVER_PREFIX); 36 | viewResolver.setSuffix(VIEW_RESOLVER_SUFFIX); 37 | return viewResolver; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/js/src/pages/start/dashboard.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Sidebar 3 | */ 4 | 5 | /* Hide for mobile, show later */ 6 | .sidebar { 7 | display: none; 8 | } 9 | @media (min-width: 768px) { 10 | .sidebar { 11 | position: fixed; 12 | top: 51px; 13 | bottom: 0; 14 | z-index: 1000; 15 | display: block; 16 | padding: 20px; 17 | overflow-x: hidden; 18 | overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */ 19 | background-color: #F8F8FF; 20 | border-right: 1px solid #eee; 21 | } 22 | } 23 | 24 | @media (min-width: 1170px) { 25 | .sidebar { 26 | width: 12%; 27 | } 28 | } 29 | 30 | /* Sidebar navigation */ 31 | .nav-sidebar { 32 | margin-right: -21px; /* 20px padding + 1px border */ 33 | margin-bottom: 20px; 34 | margin-left: -20px; 35 | } 36 | .nav-sidebar > li > a { 37 | padding-right: 20px; 38 | padding-left: 20px; 39 | color: #8A2BE2; 40 | } 41 | .nav-sidebar > .active > a, 42 | .nav-sidebar > .active > a:hover, 43 | .nav-sidebar > .active > a:focus { 44 | color: #fff; 45 | background-color: #8A2BE2; 46 | } 47 | 48 | /* 49 | * Main content 50 | */ 51 | 52 | .main { 53 | padding: 20px; 54 | } 55 | @media (min-width: 768px) { 56 | .main { 57 | padding-left: 60px; 58 | } 59 | } 60 | .main .page-header { 61 | margin-top: 0; 62 | } 63 | .main .section { 64 | margin-bottom: 20px; 65 | } 66 | 67 | 68 | /* 69 | * Placeholder dashboard ideas 70 | */ 71 | 72 | .placeholders { 73 | margin-bottom: 30px; 74 | text-align: center; 75 | } 76 | .placeholders h4 { 77 | margin-bottom: 0; 78 | } 79 | .placeholder { 80 | margin-bottom: 20px; 81 | } 82 | .placeholder img { 83 | display: inline-block; 84 | border-radius: 50%; 85 | } 86 | 87 | .dir-desc pre span { 88 | color: blue; 89 | } 90 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/jsp/contact/index.jsp: -------------------------------------------------------------------------------- 1 | <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" isELIgnored="false" %> 2 | <%@include file="../include/init.jsp"%> 3 | 4 | 5 | 6 | WEBPACK-JSP 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |
18 | Generic placeholder thumbnail 19 |

新浪微博-念念不忘秦

20 | 欢迎关注 21 |
22 |
23 | Generic placeholder thumbnail 24 |

微信公众号-秦晋之巅

25 | 欢迎关注 26 |
27 |
28 | Generic placeholder thumbnail 29 |

支付宝-付款码

30 | 如果觉得这对您有帮助可以请我喝一杯咖啡 31 |
32 |
33 |
34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/jsp/index/index.jsp: -------------------------------------------------------------------------------- 1 | <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" isELIgnored="false" %> 2 | <%@include file="../include/init.jsp"%> 3 | 4 | 5 | 6 | WEBPACK-JSP 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 | 19 | 20 |

WEBPACK + JSP 构建多页应用

21 |

传统的JSP页面应用无法有效的使用ES6语法特性,项目打包压缩困难,无法热更新。传统的单页应用在Tomcat等容器下无法进行服务端渲染从而达到SEO的效果。本项目工程很好融合的传统JSP页面服务端渲染的特点和单页应用开发特性且极易上手使用!

22 |

开始使用 23 |

24 |
25 |
26 | 27 |
28 | 29 |
30 |
31 |

WEBPACK

32 |

语法转换,打包,压缩,热更新

33 |
34 |
35 |

JSP

36 |

热部署,服务端渲染SEO

37 |
38 |
39 |

鱼与熊掌兼得

40 |

吸收WEBPACK和JSP优点,使用简单

41 |
42 |
43 |
44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/main/webapp/static/js/start.d7ebb5145fef16460537.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([1],{"0iPh":function(e,n){e.exports=window.$},1:function(e,n,t){t("cZNe"),e.exports=t("IHve")},IHve:function(e,n,t){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var o=(t("i5Z1"),t("a2c4"),t("0iPh")),i=t.n(o),r=t("4bK6"),s=t.n(r),a={data:function(){return{message:"该项目已经默认支持Vue。这一章节也是用VUE编写的,你可以尽情的享受VUE带来的编码的快乐。"}}},l=function(){var e=this,n=e.$createElement,t=e._self._c||n;return t("div",[t("p",[e._v(e._s(e.message))]),e._v(" "),e._m(0)])},c=[function(){var e=this,n=e.$createElement,t=e._self._c||n;return t("ul",[t("li",[e._v("您可以给idea添加vue.js插件,这样也可以直接使用.vue文件。")]),e._v(" "),t("li",[e._v("js和css的语法转换在.vue文件中同样适用。")])])}],u={render:l,staticRenderFns:c},h=u,p=t("VU/8"),f=p(a,h,!1,null,null,null),m=f.exports;i()('a.js-scroll-trigger[href*="#"]:not([href="#"])').click(function(){if(console.log(location.pathname,this.pathname),location.pathname.replace(/^\//,"")===this.pathname.replace(/^\//,"")&&location.hostname===this.hostname){console.log(this.hash);var e=i()(this.hash);if(e=e.length?e:i()("[name="+this.hash.slice(1)+"]"),e.length)return i()("html, body").animate({scrollTop:e.offset().top-60},300),!1}}),i()(".js-scroll-trigger").click(function(){i()(".navbar-collapse").collapse("hide")}),i()("body").scrollspy({target:"#sideNav",offset:80}),new s.a({el:"#vue-app",components:{myComponent:m}})},"Pp/C":function(e,n){!function(){for(var e,n=function(){},t=["assert","clear","count","debug","dir","dirxml","error","exception","group","groupCollapsed","groupEnd","info","log","markTimeline","profile","profileEnd","table","time","timeEnd","timeStamp","trace","warn"],o=t.length,i=window.console=window.console||{};o--;)e=t[o],i[e]||(i[e]=n)}()},a2c4:function(e,n){},cZNe:function(e,n,t){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var o=t("SbJX"),i=t.n(o);window.Promise=i.a;t("Pp/C"),t("cUYv"),t("PPkL"),t("0K64"),t("X8hh"),t("kLF+"),t("fB7P"),t("mBqO"),t("oFcf"),t("7N90"),t("wu3h"),t("SldL"),t("rplX")},h2zT:function(e,n){},i5Z1:function(e,n,t){"use strict";var o=t("h2zT");t.n(o)}},[1]); 2 | //# sourceMappingURL=start.d7ebb5145fef16460537.js.map -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | encodingFilter 10 | 11 | org.springframework.web.filter.CharacterEncodingFilter 12 | 13 | 14 | encoding 15 | utf-8 16 | 17 | 18 | forceEncoding 19 | true 20 | 21 | 22 | 23 | 24 | encodingFilter 25 | /* 26 | 27 | 28 | 29 | default 30 | *.css 31 | *.js 32 | *.html 33 | *.gif 34 | *.jpg 35 | *.jpeg 36 | *.png 37 | *.svg 38 | *.mp4 39 | *.mp3 40 | *.txt 41 | *.ico 42 | *.woff 43 | *.woff2 44 | *.ttf 45 | *.eot 46 | *.map 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /src/main/java/net/qjzd/wjsp/config/MvcConfig.java: -------------------------------------------------------------------------------- 1 | package net.qjzd.wjsp.config; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.ComponentScan; 6 | import org.springframework.context.annotation.ComponentScan.Filter; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.context.annotation.FilterType; 9 | import org.springframework.stereotype.Component; 10 | import org.springframework.stereotype.Controller; 11 | import org.springframework.stereotype.Repository; 12 | import org.springframework.stereotype.Service; 13 | import org.springframework.web.servlet.config.annotation.EnableWebMvc; 14 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 15 | import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; 16 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 17 | 18 | /** 19 | *

Title:

20 | *

Description:

21 | *

Copyright: Copyright (c) 2016

22 | *

Company:ND Co., Ltd.

23 | *

Create Time: 2017/6/13

24 | * 25 | * @author nianqin 26 | */ 27 | @Configuration 28 | @EnableWebMvc 29 | @ComponentScan(basePackages = "net.qjzd.*", includeFilters = { 30 | @Filter(type= FilterType.ANNOTATION, value=Repository.class), 31 | @Filter(type= FilterType.ANNOTATION, value=Controller.class), 32 | @Filter(type= FilterType.ANNOTATION, value=Service.class), 33 | @Filter(type= FilterType.ANNOTATION, value=Component.class) 34 | }) 35 | public class MvcConfig extends WebMvcConfigurerAdapter { 36 | 37 | @Autowired 38 | private GlobalInterceptor globalInterceptor; 39 | 40 | @Override 41 | public void addResourceHandlers(ResourceHandlerRegistry registry) { 42 | super.addResourceHandlers(registry); 43 | } 44 | 45 | @Override 46 | public void addInterceptors(InterceptorRegistry registry) { 47 | registry.addInterceptor(globalInterceptor) 48 | .addPathPatterns("/**"); 49 | super.addInterceptors(registry); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/js/src/static/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | encodingFilter 10 | 11 | org.springframework.web.filter.CharacterEncodingFilter 12 | 13 | 14 | encoding 15 | utf-8 16 | 17 | 18 | forceEncoding 19 | true 20 | 21 | 22 | 23 | 24 | encodingFilter 25 | /* 26 | 27 | 28 | 29 | default 30 | *.css 31 | *.js 32 | *.html 33 | *.gif 34 | *.jpg 35 | *.jpeg 36 | *.png 37 | *.svg 38 | *.mp4 39 | *.mp3 40 | *.txt 41 | *.ico 42 | *.woff 43 | *.woff2 44 | *.ttf 45 | *.eot 46 | *.map 47 | *.json 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /src/main/java/net/qjzd/utils/ReflectUtils.java: -------------------------------------------------------------------------------- 1 | package net.qjzd.utils; 2 | 3 | import org.springframework.util.Assert; 4 | 5 | import java.lang.annotation.Annotation; 6 | import java.lang.reflect.Method; 7 | 8 | /** 9 | *

Title:

10 | *

Description:

11 | *

Copyright: Copyright (c) 2016

12 | *

Company:ND Co., Ltd.

13 | *

Create Time: 2017/6/21

14 | * 15 | * @author nianqin 16 | */ 17 | public class ReflectUtils { 18 | 19 | /** 20 | * 查找方法,方法需要包含特定的注解 21 | * @param clazz 22 | * @param name 23 | * @param annotationType 24 | * @return 25 | */ 26 | public static Method findMethod(Class clazz, String name, Class annotationType) { 27 | Assert.notNull(clazz, "Class must not be null"); 28 | Assert.notNull(name, "Method name must not be null"); 29 | Class searchType = clazz; 30 | while (searchType != null) { 31 | Method[] methods = (searchType.isInterface() ? searchType.getMethods() : searchType.getDeclaredMethods()); 32 | for (Method method : methods) { 33 | if (name.equals(method.getName()) && annotationType != null) { 34 | Annotation[] annotations = method.getDeclaredAnnotations(); 35 | for (int i = 0; i < annotations.length; i++) { 36 | if (annotations[i].annotationType() == annotationType) { 37 | return method; 38 | } 39 | } 40 | } 41 | } 42 | searchType = searchType.getSuperclass(); 43 | } 44 | return null; 45 | } 46 | 47 | /** 48 | * 类是否包含某一个注解 49 | * @param clazz 50 | * @param annotationType 51 | * @return 52 | */ 53 | public static Boolean hasAnnotatioin(Class clazz, Class annotationType) { 54 | Assert.notNull(clazz, "Class must not be null"); 55 | Class searchType = clazz; 56 | while (searchType != null) { 57 | Annotation[] annotations = searchType.getAnnotations(); 58 | for (int i = 0; i < annotations.length; i++) { 59 | if (annotations[i].annotationType() == annotationType) { 60 | return true; 61 | } 62 | } 63 | searchType = searchType.getSuperclass(); 64 | } 65 | return false; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/net/qjzd/wjsp/exception/GlobalControllerAdvice.java: -------------------------------------------------------------------------------- 1 | package net.qjzd.wjsp.exception; 2 | 3 | import net.qjzd.utils.RequestUtils; 4 | import net.qjzd.utils.I18nUtil; 5 | import org.springframework.http.HttpStatus; 6 | import org.springframework.http.ResponseEntity; 7 | import org.springframework.web.bind.annotation.ControllerAdvice; 8 | import org.springframework.web.bind.annotation.ExceptionHandler; 9 | import org.springframework.web.bind.annotation.ResponseStatus; 10 | import org.springframework.web.context.request.WebRequest; 11 | import org.springframework.web.servlet.NoHandlerFoundException; 12 | 13 | import javax.servlet.http.HttpServletResponse; 14 | 15 | 16 | /** 17 | *

Title:

18 | *

Description:

19 | *

Copyright: Copyright (c) 2016

20 | *

Company:ND Co., Ltd.

21 | *

Create Time: 2017/6/12

22 | * 23 | * @author nianqin 24 | */ 25 | @ControllerAdvice 26 | public class GlobalControllerAdvice { 27 | 28 | @ExceptionHandler(NoHandlerFoundException.class) 29 | @ResponseStatus(HttpStatus.NOT_FOUND) 30 | public String notFoundExceptionHandler(NoHandlerFoundException e, WebRequest request, HttpServletResponse response) { 31 | if (RequestUtils.isTextHtmlRequest(request) 32 | && !RequestUtils.isControllerReturnJsonAction(e.getStackTrace())) { 33 | return "index/index"; 34 | } 35 | ResponseEntity entity = new ResponseEntity<>( 36 | new ErrorMessage(ErrorCode.URI_NOT_FOUND.getCode(), 37 | I18nUtil.getMessage(ErrorCode.URI_NOT_FOUND.getCode()), 38 | e.getMessage()), 39 | HttpStatus.NOT_FOUND); 40 | RequestUtils.write(response, entity); 41 | return null; 42 | } 43 | 44 | @ExceptionHandler() 45 | public String defaultErrorHandler(Exception e, WebRequest request, HttpServletResponse response) { 46 | if (RequestUtils.isTextHtmlRequest(request) 47 | && !RequestUtils.isControllerReturnJsonAction(e.getStackTrace())) { 48 | return "error"; 49 | } 50 | ResponseEntity entity = new ResponseEntity<>( 51 | new ErrorMessage(ErrorCode.INTERNAL_SERVER_ERROR.getCode(), 52 | I18nUtil.getMessage(ErrorCode.INTERNAL_SERVER_ERROR.getCode()), 53 | e.getMessage()), 54 | HttpStatus.INTERNAL_SERVER_ERROR); 55 | RequestUtils.write(response, entity); 56 | return null; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/net/qjzd/utils/LogUtil.java: -------------------------------------------------------------------------------- 1 | package net.qjzd.utils; 2 | 3 | import org.apache.commons.logging.LogFactory; 4 | import org.apache.log4j.Logger; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * 系统业务日志 10 | */ 11 | public final class LogUtil { 12 | 13 | public static void exceptionLog(Logger log,Exception e){ 14 | if(e==null) 15 | return; 16 | StringBuffer str = new StringBuffer(e.getClass().getName()); 17 | str.append(":").append(e.getMessage()); 18 | StackTraceElement[] stack = e.getStackTrace(); 19 | for(StackTraceElement ee:stack){ 20 | str.append("\n").append(ee.toString()); 21 | } 22 | log.error(str.toString()); 23 | e.printStackTrace(); 24 | } 25 | 26 | public static String exceptionLog(Throwable t) { 27 | if(t == null) 28 | return ""; 29 | StringBuffer str = new StringBuffer(t.getClass().getName()); 30 | str.append(":").append(t.getMessage()); 31 | StackTraceElement[] stack = t.getStackTrace(); 32 | for(StackTraceElement ee:stack){ 33 | str.append("\n").append(ee.toString()); 34 | } 35 | Logger.getRootLogger().error(str.toString()); 36 | return str.toString(); 37 | } 38 | 39 | public static String exceptionLog(Exception e) { 40 | if(e == null) 41 | return ""; 42 | StringBuffer str = new StringBuffer(e.getClass().getName()); 43 | str.append(":").append(e.getMessage()); 44 | StackTraceElement[] stack = e.getStackTrace(); 45 | for(StackTraceElement ee:stack){ 46 | str.append("\n").append(ee.toString()); 47 | } 48 | Logger.getRootLogger().error(str.toString()); 49 | return str.toString(); 50 | } 51 | 52 | public static void debugLog(String info) { 53 | Logger.getRootLogger().debug(info); 54 | } 55 | 56 | /*******网上营业厅新增********/ 57 | 58 | public static void infoLog(Class theme, String info) { 59 | LogFactory.getLog(theme).info(info); 60 | } 61 | 62 | public static void infoLog(Class theme, Object[] infos) { 63 | for (int i = 0; i < infos.length; i++) { 64 | LogFactory.getLog(theme).info(infos[i]); 65 | } 66 | } 67 | 68 | public static void infoLog(Class theme, List infos) { 69 | for (int i = 0; i < infos.size(); i++) { 70 | LogFactory.getLog(theme).info(infos.get(i)); 71 | } 72 | } 73 | 74 | public static void infoLog(String info) { 75 | Logger.getRootLogger().info(info); 76 | } 77 | 78 | public static void errorLog(Class theme, String info) { 79 | LogFactory.getLog(theme).error(info); 80 | } 81 | 82 | public static void errorLog(Class theme, String info, Exception e) { 83 | LogFactory.getLog(theme).error(info, e); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/js/build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const webpack = require('webpack') 4 | const config = require('../config') 5 | const merge = require('webpack-merge') 6 | const baseWebpackConfig = require('./webpack.base.conf') 7 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') 8 | const portfinder = require('portfinder') 9 | 10 | const devWebpackConfig = merge(baseWebpackConfig, { 11 | module: { 12 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true }) 13 | }, 14 | // cheap-module-eval-source-map is faster for development 15 | devtool: config.dev.devtool, 16 | 17 | // these devServer options should be customized in /config/index.js 18 | // webpack-dev-server不要升级到2.8.0版本以上,否则将无法支持IE9,IE10。 19 | // 具体看,https://github.com/webpack/webpack-dev-server/issues/1143或者https://github.com/webpack/webpack-dev-server#caveats 20 | devServer: { 21 | clientLogLevel: 'warning', 22 | historyApiFallback: true, 23 | disableHostCheck: true, // 支持本地IP访问 24 | hot: true, 25 | host: process.env.HOST || config.dev.host, 26 | port: process.env.PORT || config.dev.port, 27 | open: config.dev.autoOpenBrowser, 28 | overlay: config.dev.errorOverlay ? { 29 | warnings: false, 30 | errors: true, 31 | } : false, 32 | publicPath: config.dev.assetsPublicPath, 33 | proxy: config.dev.proxyTable, 34 | quiet: true, // necessary for FriendlyErrorsPlugin 35 | watchOptions: { 36 | poll: config.dev.poll, 37 | } 38 | }, 39 | plugins: [ 40 | new webpack.DefinePlugin({ 41 | 'process.env': require('../config/dev.env') 42 | }), 43 | new webpack.HotModuleReplacementPlugin(), 44 | new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update. 45 | new webpack.NoEmitOnErrorsPlugin() 46 | ] 47 | }) 48 | 49 | module.exports = new Promise((resolve, reject) => { 50 | portfinder.basePort = process.env.PORT || config.dev.port 51 | portfinder.getPort((err, port) => { 52 | if (err) { 53 | reject(err) 54 | } else { 55 | // publish the new Port, necessary for e2e tests 56 | process.env.PORT = port 57 | // add port to devServer config 58 | devWebpackConfig.devServer.port = port 59 | 60 | // Add FriendlyErrorsPlugin 61 | devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({ 62 | compilationSuccessInfo: { 63 | messages: [`Your application is running here: http://${config.dev.host}:${port}`], 64 | }, 65 | onErrors: config.dev.notifyOnErrors 66 | ? utils.createNotifierCallback() 67 | : undefined 68 | })) 69 | 70 | resolve(devWebpackConfig) 71 | } 72 | }) 73 | }) 74 | -------------------------------------------------------------------------------- /src/main/js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webpack-jsp", 3 | "version": "1.0.0", 4 | "description": "webpack jsp demo", 5 | "author": "nianqin", 6 | "license": "MIT", 7 | "scripts": { 8 | "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", 9 | "clean": "node build/clean.js", 10 | "build": "node build/build.js" 11 | }, 12 | "dependencies": { 13 | "copy-webpack-plugin": "^4.5.1", 14 | "core-js": "^2.5.3", 15 | "nuo": "^1.0.0", 16 | "vue": "^2.5.2", 17 | "vue-router": "^3.0.1", 18 | "whatwg-fetch": "^2.0.3" 19 | }, 20 | "devDependencies": { 21 | "autoprefixer": "^7.1.2", 22 | "babel-core": "^6.22.1", 23 | "babel-eslint": "^7.1.1", 24 | "babel-jest": "^21.0.2", 25 | "babel-loader": "^7.1.1", 26 | "babel-plugin-transform-runtime": "^6.22.0", 27 | "babel-preset-env": "^1.3.2", 28 | "babel-preset-stage-2": "^6.22.0", 29 | "babel-register": "^6.22.0", 30 | "chalk": "^2.0.1", 31 | "cross-env": "^5.0.0", 32 | "cross-spawn": "^5.0.1", 33 | "css-loader": "^0.28.0", 34 | "eslint": "^3.19.0", 35 | "eslint-config-standard": "^10.2.1", 36 | "eslint-friendly-formatter": "^3.0.0", 37 | "eslint-loader": "^1.7.1", 38 | "eslint-plugin-html": "^3.0.0", 39 | "eslint-plugin-import": "^2.7.0", 40 | "eslint-plugin-node": "^5.2.0", 41 | "eslint-plugin-promise": "^3.4.0", 42 | "eslint-plugin-standard": "^3.0.1", 43 | "eventsource-polyfill": "^0.9.6", 44 | "extract-text-webpack-plugin": "^3.0.0", 45 | "file-loader": "^1.1.4", 46 | "friendly-errors-webpack-plugin": "^1.6.1", 47 | "glob": "^7.0.0", 48 | "html-loader": "^0.4.3", 49 | "html-webpack-plugin": "^3.1.0", 50 | "jest": "^21.2.0", 51 | "less": "^2.6.0", 52 | "less-loader": "^2.2.2", 53 | "nightwatch": "^0.9.12", 54 | "node-notifier": "^5.1.2", 55 | "optimize-css-assets-webpack-plugin": "^3.2.0", 56 | "ora": "^1.2.0", 57 | "portfinder": "^1.0.13", 58 | "postcss-import": "^11.0.0", 59 | "postcss-loader": "^2.0.8", 60 | "postcss-nested": "^3.0.0", 61 | "postcss-url": "^7.3.0", 62 | "raw-loader": "^0.5.1", 63 | "rimraf": "^2.6.0", 64 | "selenium-server": "^3.0.1", 65 | "semver": "^5.3.0", 66 | "shelljs": "^0.7.6", 67 | "url-loader": "^0.5.8", 68 | "vue-jest": "^1.0.2", 69 | "vue-loader": "^13.3.0", 70 | "vue-style-loader": "^3.0.1", 71 | "vue-template-compiler": "^2.5.2", 72 | "webpack": "^3.6.0", 73 | "webpack-bundle-analyzer": "^2.9.0", 74 | "webpack-dev-server": "2.7.1", 75 | "webpack-merge": "^4.1.0", 76 | "write-file-webpack-plugin": "^4.2.0" 77 | }, 78 | "engines": { 79 | "node": ">= 4.0.0", 80 | "npm": ">= 3.0.0" 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/js/config/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | // Template version: 1.2.3 3 | // see http://vuejs-templates.github.io/webpack for documentation. 4 | 5 | const path = require('path') 6 | 7 | module.exports = { 8 | dev: { 9 | // Paths 10 | assetsSubDirectory: 'static', 11 | assetsPublicPath: '/', 12 | proxyTable: { 13 | '*': 'http://localhost:8080' 14 | }, 15 | // Various Dev Server settings 16 | host: '0.0.0.0', // 'localhost' can be overwritten by process.env.HOST ‘0.0.0.0’binds to all hosts and use disableHostCheck: true, 17 | port: 8081, // can be overwritten by process.env.HOST, if port is in use, a free one will be determined 18 | autoOpenBrowser: false, 19 | errorOverlay: true, 20 | notifyOnErrors: true, 21 | poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions- 22 | 23 | // Use Eslint Loader? 24 | // If true, your code will be linted during bundling and 25 | // linting errors and warnings will be shown in the console. 26 | useEslint: true, 27 | // If true, eslint errors and warnings will also be shown in the error overlay 28 | // in the browser. 29 | showEslintErrorsInOverlay: false, 30 | 31 | /** 32 | * Source Maps 33 | */ 34 | 35 | // https://webpack.js.org/configuration/devtool/#development 36 | devtool: 'eval-source-map', 37 | 38 | // If you have problems debugging vue-files in devtools, 39 | // set this to false - it *may* help 40 | // https://vue-loader.vuejs.org/en/options.html#cachebusting 41 | cacheBusting: true, 42 | 43 | // CSS Sourcemaps off by default because relative paths are "buggy" 44 | // with this option, according to the CSS-Loader README 45 | // (https://github.com/webpack/css-loader#sourcemaps) 46 | // In our experience, they generally work as expected, 47 | // just be aware of this issue when enabling this option. 48 | cssSourceMap: false, 49 | }, 50 | 51 | build: { 52 | // Paths 53 | assetsRoot: path.resolve(__dirname, '../../webapp'), 54 | assetsSubDirectory: 'static', 55 | assetsPublicPath: '/', 56 | 57 | /** 58 | * Source Maps 59 | */ 60 | 61 | productionSourceMap: true, 62 | // https://webpack.js.org/configuration/devtool/#production 63 | devtool: '#source-map', 64 | 65 | // Gzip off by default as many popular static hosts such as 66 | // Surge or Netlify already gzip all static assets for you. 67 | // Before setting to `true`, make sure to: 68 | // npm install --save-dev compression-webpack-plugin 69 | productionGzip: false, 70 | productionGzipExtensions: ['js', 'css'], 71 | 72 | // Run the build command with an extra argument to 73 | // View the bundle analyzer report after build finishes: 74 | // `npm run build --report` 75 | // Set to `true` or `false` to always turn it on or off 76 | bundleAnalyzerReport: process.env.npm_config_report 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/net/qjzd/utils/RequestUtils.java: -------------------------------------------------------------------------------- 1 | package net.qjzd.utils; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import net.qjzd.wjsp.exception.ErrorMessage; 5 | import org.springframework.http.ResponseEntity; 6 | import org.springframework.web.bind.annotation.ResponseBody; 7 | import org.springframework.web.bind.annotation.RestController; 8 | import org.springframework.web.context.request.WebRequest; 9 | 10 | import javax.servlet.http.HttpServletResponse; 11 | import java.io.IOException; 12 | import java.io.PrintWriter; 13 | import java.lang.reflect.Method; 14 | 15 | /** 16 | *

Title:

17 | *

Description:

18 | *

Copyright: Copyright (c) 2016

19 | *

Company:ND Co., Ltd.

20 | *

Create Time: 2017/6/21

21 | * 22 | * @author nianqin 23 | */ 24 | public class RequestUtils { 25 | 26 | /** 27 | * 写请求 28 | * @param response 29 | * @param entity 30 | */ 31 | public static void write(HttpServletResponse response, ResponseEntity entity) { 32 | response.setStatus(entity.getStatusCode().value()); 33 | response.setContentType("application/json;charset=UTF-8"); 34 | try { 35 | PrintWriter writer = response.getWriter(); 36 | writer.print(JSON.toJSONString(entity.getBody())); 37 | writer.flush(); 38 | writer.close(); 39 | } catch (IOException e) { 40 | e.printStackTrace(); 41 | } 42 | } 43 | 44 | /** 45 | * 通过头部的accept的,如果带有text/html 46 | * @param request 47 | * @return 48 | */ 49 | public static Boolean isTextHtmlRequest(WebRequest request) { 50 | String accept = String.valueOf(request.getHeader("Accept")); 51 | return accept.indexOf("text/html") >= 0; 52 | } 53 | 54 | /*** 55 | * 判断controller是否含有注解RestController或者方法是否含有注解ResponseBody 56 | * @param stackTraceElement 57 | * @return 58 | */ 59 | public static boolean isControllerReturnJsonAction(StackTraceElement stackTraceElement) { 60 | String className = stackTraceElement.getClassName(); 61 | if (className.endsWith("Controller")) { 62 | try { 63 | Class controllerClass = Class.forName(className); 64 | if (ReflectUtils.hasAnnotatioin(controllerClass, RestController.class)) { 65 | return true; 66 | } 67 | Method actionMethod = ReflectUtils.findMethod(controllerClass, stackTraceElement.getMethodName(), ResponseBody.class); 68 | if (null != actionMethod) { 69 | return true; 70 | } 71 | } catch (ClassNotFoundException e) { 72 | e.printStackTrace(); 73 | } 74 | } 75 | return false; 76 | } 77 | 78 | /*** 79 | * 判断接口的注解是否是ResponseBody,是,那么返回json,而不是跳转错误页面
80 | * 限制最多循环10次,否则影响性能 81 | * @param stackTraceElements 82 | * @return 83 | */ 84 | public static boolean isControllerReturnJsonAction(StackTraceElement[] stackTraceElements) { 85 | int length = stackTraceElements.length; 86 | for (int i = 0; i < length; i++) { 87 | StackTraceElement stackTraceElement = stackTraceElements[i]; 88 | if (isControllerReturnJsonAction(stackTraceElement)) { 89 | return true; 90 | } 91 | } 92 | return false; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/net/qjzd/wjsp/config/WebAppConfig.java: -------------------------------------------------------------------------------- 1 | package net.qjzd.wjsp.config; 2 | 3 | import org.springframework.web.WebApplicationInitializer; 4 | import org.springframework.web.context.ContextLoaderListener; 5 | import org.springframework.web.context.WebApplicationContext; 6 | import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; 7 | import org.springframework.web.filter.CharacterEncodingFilter; 8 | import org.springframework.web.servlet.DispatcherServlet; 9 | 10 | import javax.servlet.*; 11 | import java.util.EnumSet; 12 | 13 | /** 14 | *

Title:

15 | *

Description:

16 | *

Copyright: Copyright (c) 2016

17 | *

Company:ND Co., Ltd.

18 | *

Create Time: 2017/6/13

19 | * 20 | * @author nianqin 21 | */ 22 | public class WebAppConfig implements WebApplicationInitializer { 23 | private static final String CHARACTER_ENCODING_FILTER_ENCODING = "UTF-8"; 24 | private static final String CHARACTER_ENCODING_FILTER_NAME = "characterEncoding"; 25 | private static final String CHARACTER_ENCODING_FILTER_URL_PATTERN = "/*"; 26 | 27 | private static final String CORS_FILTER_NAME = "crossOrigin"; 28 | private static final String CORS_FILTER_URL_PATTERN = "/*"; 29 | 30 | private static final String DISPATCHER_SERVLET_NAME = "dispatcher"; 31 | private static final String DISPATCHER_SERVLET_MAPPING = "/"; 32 | 33 | @Override 34 | public void onStartup(ServletContext servletContext) throws ServletException { 35 | AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext(); 36 | rootContext.register(MvcConfig.class); 37 | 38 | configureDispatcherServlet(servletContext, rootContext); 39 | EnumSet dispatcherTypes = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD); 40 | configureCharacterEncodingFilter(servletContext, dispatcherTypes); 41 | configureCorsFilter(servletContext, dispatcherTypes); 42 | servletContext.addListener(new ContextLoaderListener(rootContext)); 43 | } 44 | 45 | private void configureDispatcherServlet(ServletContext servletContext, WebApplicationContext rootContext) { 46 | ServletRegistration.Dynamic dispatcher = servletContext.addServlet( 47 | DISPATCHER_SERVLET_NAME, 48 | new DispatcherServlet(rootContext) 49 | ); 50 | dispatcher.setLoadOnStartup(1); 51 | dispatcher.addMapping(DISPATCHER_SERVLET_MAPPING); 52 | // https://stackoverflow.com/questions/28364564/how-to-catch-spring-pagenotfound-exception-in-dispatcherservlet-context-without 53 | dispatcher.setInitParameter("throwExceptionIfNoHandlerFound", "true"); 54 | } 55 | 56 | private void configureCharacterEncodingFilter(ServletContext servletContext, EnumSet dispatcherTypes) { 57 | CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter(); 58 | characterEncodingFilter.setEncoding(CHARACTER_ENCODING_FILTER_ENCODING); 59 | characterEncodingFilter.setForceEncoding(true); 60 | FilterRegistration.Dynamic characterEncoding = servletContext.addFilter(CHARACTER_ENCODING_FILTER_NAME, characterEncodingFilter); 61 | characterEncoding.addMappingForUrlPatterns(dispatcherTypes, true, CHARACTER_ENCODING_FILTER_URL_PATTERN); 62 | } 63 | 64 | private void configureCorsFilter(ServletContext servletContext, EnumSet dispatcherTypes) { 65 | CorsFilter corsFilter = new CorsFilter(); 66 | FilterRegistration.Dynamic cors = servletContext.addFilter(CORS_FILTER_NAME, corsFilter); 67 | cors.addMappingForUrlPatterns(dispatcherTypes, true, CORS_FILTER_URL_PATTERN); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/js/build/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | var glob = require('glob') 4 | const config = require('../config') 5 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 6 | const pkg = require('../package.json') 7 | 8 | const rootPathResolve = function () { 9 | return path.resolve.apply(path.resolve, [__dirname, '..'].concat(Array.prototype.slice.call(arguments))) 10 | } 11 | 12 | const pathResolve = { 13 | root: rootPathResolve, 14 | src: function () { 15 | return rootPathResolve.apply(rootPathResolve, ['src'].concat(Array.prototype.slice.call(arguments))) 16 | }, 17 | dist: function () { 18 | return rootPathResolve.apply(rootPathResolve, ['../webapp'].concat(Array.prototype.slice.call(arguments))) 19 | } 20 | } 21 | 22 | exports.pathResolve = pathResolve 23 | 24 | exports.assetsPath = function (_path) { 25 | const assetsSubDirectory = process.env.NODE_ENV === 'production' 26 | ? config.build.assetsSubDirectory 27 | : config.dev.assetsSubDirectory 28 | return path.posix.join(assetsSubDirectory, _path) 29 | } 30 | 31 | exports.cssLoaders = function (options) { 32 | options = options || {} 33 | 34 | const cssLoader = { 35 | loader: 'css-loader', 36 | options: { 37 | sourceMap: options.sourceMap 38 | } 39 | } 40 | 41 | var postcssLoader = { 42 | loader: 'postcss-loader', 43 | options: { 44 | sourceMap: options.sourceMap 45 | } 46 | } 47 | 48 | // generate loader string to be used with extract text plugin 49 | function generateLoaders (loader, loaderOptions) { 50 | const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader] 51 | if (loader) { 52 | loaders.push({ 53 | loader: loader + '-loader', 54 | options: Object.assign({}, loaderOptions, { 55 | sourceMap: options.sourceMap 56 | }) 57 | }) 58 | } 59 | // Extract CSS when that option is specified 60 | // (which is the case during production build) 61 | if (options.extract) { 62 | return ExtractTextPlugin.extract({ 63 | use: loaders, 64 | fallback: 'vue-style-loader' 65 | }) 66 | } else { 67 | return ['vue-style-loader'].concat(loaders) 68 | } 69 | } 70 | 71 | return { 72 | css: generateLoaders(), 73 | postcss: generateLoaders(), 74 | less: generateLoaders('less'), 75 | sass: generateLoaders('sass', { indentedSyntax: true }), 76 | scss: generateLoaders('sass'), 77 | stylus: generateLoaders('stylus'), 78 | styl: generateLoaders('stylus') 79 | } 80 | } 81 | 82 | exports.styleLoaders = function (options) { 83 | const output = [] 84 | const loaders = exports.cssLoaders(options) 85 | for (const extension in loaders) { 86 | const loader = loaders[extension] 87 | output.push({ 88 | test: new RegExp('\\.' + extension + '$'), 89 | use: loader 90 | }) 91 | } 92 | return output 93 | } 94 | 95 | exports.createNotifierCallback = function () { 96 | const notifier = require('node-notifier') 97 | 98 | return (severity, errors) => { 99 | if (severity !== 'error') { 100 | return 101 | } 102 | const error = errors[0] 103 | 104 | const filename = error.file.split('!').pop() 105 | notifier.notify({ 106 | title: pkg.name, 107 | message: severity + ': ' + error.name, 108 | subtitle: filename || '', 109 | icon: path.join(__dirname, 'logo.png') 110 | }) 111 | } 112 | } 113 | 114 | exports.getJspMapPath = function () { 115 | const list = [] 116 | var files = glob.sync(pathResolve.src('pages/**/*.jsp')) 117 | for (let i = 0; i < files.length; i++) { 118 | let srcFilePath = path.normalize(files[i]) 119 | list.push({ 120 | src: srcFilePath, 121 | dist: srcFilePath.replace(pathResolve.src('pages'), pathResolve.dist('WEB-INF/jsp')) 122 | }) 123 | } 124 | return list 125 | } 126 | -------------------------------------------------------------------------------- /src/main/js/src/styles/index.css: -------------------------------------------------------------------------------- 1 | @import "bootstrap/css/bootstrap"; 2 | 3 | /* 4 | * Override Bootstrap's default container. 5 | */ 6 | body { 7 | font-family: "Helvetica Neue", "Helvetica", "Lucida Grande", "Arial", "Hiragino Sans GB", "Microsoft Yahei", "WenQuanYi Micro Hei", "sans-serif"; 8 | font-weight: normal; 9 | padding-top: 50px; 10 | } 11 | 12 | pre { 13 | border: none; 14 | background-color: transparent; 15 | } 16 | 17 | .jumbotron { 18 | text-align: center; 19 | background-color: #8A2BE2; 20 | color: #fff; 21 | } 22 | 23 | .jumbotron .lead em { 24 | display: none; 25 | } 26 | 27 | .jumbotron .logo { 28 | width: 100%; 29 | max-width: 200px; 30 | } 31 | 32 | .jumbotron .btn-getting-started { 33 | color: #efefef; 34 | border: none; 35 | box-shadow: inset 0 0 0 2px #efefef; 36 | border-radius: 2px; 37 | background-color: transparent; 38 | margin-top: 26px; 39 | } 40 | 41 | .jumbotron .btn-getting-started:hover, 42 | .jumbotron .btn-getting-started:active { 43 | color: #fff; 44 | box-shadow: inset 0 0 0 2px #fff; 45 | background-color: transparent; 46 | } 47 | 48 | @media (min-width: 768px) { 49 | .site-navbar .navbar-nav { 50 | float: right !important; 51 | } 52 | } 53 | 54 | .navbar-inverse { 55 | background-color: #8A2BE2; 56 | border-color: transparent; 57 | } 58 | 59 | .navbar-inverse .navbar-brand { 60 | color: #efefef; 61 | } 62 | 63 | .navbar-inverse .navbar-nav > li > a { 64 | color: #e8e8e8; 65 | } 66 | 67 | .navbar-inverse .navbar-nav > .active > a, 68 | .navbar-inverse .navbar-nav > .active > a:focus, 69 | .navbar-inverse .navbar-nav > .active > a:hover { 70 | color: #fff; 71 | background-color: transparent; 72 | } 73 | 74 | .navbar-inverse .navbar-collapse, 75 | .navbar-inverse .navbar-form { 76 | border-color: #8A2BE2; 77 | } 78 | 79 | .navbar-inverse .navbar-toggle { 80 | border-color: #fff; 81 | } 82 | 83 | .navbar-inverse .navbar-toggle:hover, 84 | .navbar-inverse .navbar-toggle:focus { 85 | background-color: transparent; 86 | } 87 | 88 | .footer { 89 | margin-top: 60px; 90 | text-align: center; 91 | color: #aaa; 92 | } 93 | 94 | .footer a { 95 | color: inherit; 96 | } 97 | 98 | .footer a:hover { 99 | text-decoration: none; 100 | color: inherit; 101 | } 102 | 103 | .docs-wrapper { 104 | margin-top: 30px; 105 | } 106 | 107 | .benefits h2 { 108 | margin-top: 40px; 109 | } 110 | 111 | .benefits p { 112 | font-size: 18px; 113 | } 114 | 115 | .markdown-body { 116 | font-size: 16px; 117 | line-height: 1.8; 118 | } 119 | 120 | .markdown-body h1, 121 | .markdown-body h2, 122 | .markdown-body h3, 123 | .markdown-body h4, 124 | .markdown-body h5, 125 | .markdown-body h6 { 126 | margin-top: 1.2em; 127 | margin-bottom: 0.6em; 128 | line-height: 1.35; 129 | } 130 | 131 | .markdown-body h6, 132 | .markdown-body h5 { 133 | font-size: 18px; 134 | } 135 | 136 | .markdown-body p, 137 | .markdown-body pre, 138 | .markdown-body ul, 139 | .markdown-body ol, 140 | .markdown-body dl, 141 | .markdown-body form, 142 | .markdown-body hr, 143 | .markdown-body table, 144 | .markdown-body blockquote { 145 | margin-bottom: 1.2em; 146 | } 147 | 148 | .markdown-body img { 149 | display: block; 150 | max-width: 100%; 151 | height: auto; 152 | } 153 | 154 | .markdown-body a { 155 | text-decoration: underline; 156 | } 157 | 158 | .markdown-body a:hover { 159 | text-decoration: underline; 160 | } 161 | 162 | .markdown-body blockquote { 163 | margin: 1em 0 1em 0; 164 | padding: 0 0 0 1.6em; 165 | } 166 | 167 | .markdown-body blockquote small { 168 | display: inline-block; 169 | margin: 0.8em 0 0.8em 1.5em; 170 | font-size: 0.9em; 171 | } 172 | 173 | .markdown-body pre { 174 | font-size: 14px; 175 | border: none; 176 | border-radius: 0; 177 | } 178 | 179 | .markdown-body hr { 180 | border-top: 1px solid #e5e5e5; 181 | } 182 | 183 | .markdown-body li ul, 184 | .markdown-body li ol { 185 | margin-bottom: 0.8em; 186 | } 187 | 188 | .sub-title { 189 | color: #FFFFFF; 190 | } 191 | .text { 192 | text-align: center; 193 | } 194 | -------------------------------------------------------------------------------- /src/main/js/build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const utils = require('./utils') 4 | const config = require('../config') 5 | const vueLoaderConfig = require('./vue-loader.conf') 6 | const HtmlWebpackPlugin = require('html-webpack-plugin') 7 | var WriteFilePlugin = require('write-file-webpack-plugin') 8 | var jsJspMapData = require('../config/js-jsp-map') 9 | const CopyWebpackPlugin = require('copy-webpack-plugin') 10 | 11 | const pathResolve = utils.pathResolve 12 | const entries = {} 13 | jsJspMapData.forEach(item => { 14 | entries[item.name] = [pathResolve.src('polyfills/index.js'), item.jsPath] 15 | }) 16 | 17 | const htmlWebpackPlugins = utils.getJspMapPath().map(function (mapEntry) { 18 | const conf = { 19 | filename: mapEntry.dist, // 生成的html存放路径,相对于path 20 | template: mapEntry.src, // html模板路径 21 | inject: false, 22 | cache: false 23 | } 24 | const indexJsp = jsJspMapData.filter(item => { 25 | return item.jspPath === mapEntry.dist 26 | })[0] 27 | if (indexJsp) { 28 | conf.inject = 'body' 29 | conf.chunks = ['manifest', 'vendor', indexJsp.name] 30 | } 31 | return new HtmlWebpackPlugin(conf) 32 | }) 33 | module.exports = { 34 | context: pathResolve.root(), 35 | entry: entries, 36 | output: { 37 | path: config.build.assetsRoot, 38 | filename: process.env.NODE_ENV === 'production' 39 | ? utils.assetsPath('js/[name].[chunkhash].js') 40 | : utils.assetsPath('js/[name].js?[hash]'), 41 | chunkFilename: process.env.NODE_ENV === 'production' 42 | ? utils.assetsPath('js/[id].chunk.[chunkhash].js') 43 | : utils.assetsPath('js/[id].chunk.js?[hash]'), 44 | publicPath: process.env.NODE_ENV === 'production' 45 | ? config.build.assetsPublicPath 46 | : config.dev.assetsPublicPath, 47 | }, 48 | resolve: { 49 | extensions: ['.js', '.vue', '.json', '.css'], 50 | alias: { 51 | vue: 'vue/dist/vue.js', 52 | '@': pathResolve.src(), 53 | } 54 | }, 55 | externals: { 56 | jquery: 'window.$' 57 | }, 58 | module: { 59 | rules: [ 60 | ...(config.dev.useEslint? [{ 61 | test: /\.(js|vue)$/, 62 | loader: 'eslint-loader', 63 | enforce: 'pre', 64 | include: [pathResolve.src()], 65 | options: { 66 | formatter: require('eslint-friendly-formatter'), 67 | emitWarning: !config.dev.showEslintErrorsInOverlay 68 | } 69 | }] : []), 70 | { 71 | test: /\.vue$/, 72 | loader: 'vue-loader', 73 | options: vueLoaderConfig 74 | }, 75 | { 76 | test: /\.js$/, 77 | loader: 'babel-loader', 78 | include: [pathResolve.src()] 79 | }, 80 | { 81 | test: /\.html$/, 82 | loader: 'html?-minimize' // 避免压缩html,https://github.com/webpack/html-loader/issues/50 83 | }, 84 | { 85 | test: /\.jsp$/, 86 | loader: 'raw-loader' 87 | }, 88 | { 89 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 90 | loader: 'url-loader', 91 | options: { 92 | limit: 10000, 93 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 94 | } 95 | }, 96 | { 97 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, 98 | loader: 'url-loader', 99 | options: { 100 | limit: 10000, 101 | name: utils.assetsPath('media/[name].[hash:7].[ext]') 102 | } 103 | }, 104 | { 105 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 106 | loader: 'url-loader', 107 | options: { 108 | limit: 10000, 109 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 110 | } 111 | } 112 | ] 113 | }, 114 | plugins: [ 115 | new CopyWebpackPlugin([ 116 | { 117 | from: pathResolve.src('static'), 118 | to: pathResolve.dist(), 119 | ignore: ['README.md'] 120 | } 121 | ]), 122 | ...htmlWebpackPlugins, 123 | // copy custom static assets 124 | new WriteFilePlugin({ 125 | // test: /^((?!\.hot-update).)*$/, 126 | test: /\.jsp|\.tld|\.xml$/, 127 | }) 128 | ] 129 | } 130 | -------------------------------------------------------------------------------- /src/main/js/build/webpack.prod.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const utils = require('./utils') 4 | const webpack = require('webpack') 5 | const config = require('../config') 6 | const merge = require('webpack-merge') 7 | const baseWebpackConfig = require('./webpack.base.conf') 8 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 9 | const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') 10 | 11 | const env = process.env.NODE_ENV === 'testing' 12 | ? require('../config/test.env') 13 | : require('../config/prod.env') 14 | 15 | const webpackConfig = merge(baseWebpackConfig, { 16 | module: { 17 | rules: utils.styleLoaders({ 18 | sourceMap: config.build.productionSourceMap, 19 | extract: true, 20 | usePostCSS: true 21 | }) 22 | }, 23 | devtool: config.build.productionSourceMap ? config.build.devtool : false, 24 | plugins: [ 25 | // http://vuejs.github.io/vue-loader/en/workflow/production.html 26 | new webpack.DefinePlugin({ 27 | 'process.env': env 28 | }), 29 | // UglifyJs do not support ES6+, you can also use babel-minify for better treeshaking: https://github.com/babel/minify 30 | new webpack.optimize.UglifyJsPlugin({ 31 | compress: { 32 | warnings: false 33 | }, 34 | sourceMap: config.build.productionSourceMap, 35 | parallel: true 36 | }), 37 | // extract css into its own file 38 | new ExtractTextPlugin({ 39 | filename: utils.assetsPath('css/[name].[contenthash].css'), 40 | // set the following option to `true` if you want to extract CSS from 41 | // codesplit chunks into this main css file as well. 42 | // This will result in *all* of your app's CSS being loaded upfront. 43 | allChunks: false, 44 | }), 45 | // Compress extracted CSS. We are using this plugin so that possible 46 | // duplicated CSS from different components can be deduped. 47 | new OptimizeCSSPlugin({ 48 | cssProcessorOptions: config.build.productionSourceMap 49 | ? { safe: true, map: { inline: false } } 50 | : { safe: true } 51 | }), 52 | // keep module.id stable when vender modules does not change 53 | new webpack.HashedModuleIdsPlugin(), 54 | // enable scope hoisting 55 | new webpack.optimize.ModuleConcatenationPlugin(), 56 | // split vendor js into its own file 57 | new webpack.optimize.CommonsChunkPlugin({ 58 | name: 'vendor', 59 | filename: utils.assetsPath('js/[name].[chunkhash].js'), 60 | minChunks: function (module) { 61 | // any required modules inside node_modules are extracted to vendor 62 | return ( 63 | module.resource && 64 | /\.js$/.test(module.resource) && 65 | module.resource.indexOf( 66 | path.join(__dirname, '../node_modules') 67 | ) === 0 68 | ) 69 | } 70 | }), 71 | // extract webpack runtime and module manifest to its own file in order to 72 | // prevent vendor hash from being updated whenever app bundle is updated 73 | new webpack.optimize.CommonsChunkPlugin({ 74 | name: 'manifest', 75 | filename: utils.assetsPath('js/[name].[chunkhash].js'), 76 | minChunks: Infinity 77 | }), 78 | // This instance extracts shared chunks from code splitted chunks and bundles them 79 | // in a separate chunk, similar to the vendor chunk 80 | // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk 81 | // new webpack.optimize.CommonsChunkPlugin({ 82 | // name: 'common-app', 83 | // async: utils.assetsPath('js/vendor-async.[chunkhash].js'), 84 | // children: true, 85 | // minChunks: 3 86 | // }) 87 | ] 88 | }) 89 | 90 | if (config.build.productionGzip) { 91 | const CompressionWebpackPlugin = require('compression-webpack-plugin') 92 | 93 | webpackConfig.plugins.push( 94 | new CompressionWebpackPlugin({ 95 | asset: '[path].gz[query]', 96 | algorithm: 'gzip', 97 | test: new RegExp( 98 | '\\.(' + 99 | config.build.productionGzipExtensions.join('|') + 100 | ')$' 101 | ), 102 | threshold: 10240, 103 | minRatio: 0.8 104 | }) 105 | ) 106 | } 107 | 108 | if (config.build.bundleAnalyzerReport) { 109 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin 110 | webpackConfig.plugins.push(new BundleAnalyzerPlugin()) 111 | } 112 | 113 | module.exports = webpackConfig 114 | -------------------------------------------------------------------------------- /src/main/webapp/images/jsp.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | 12 | 26 | 27 | 30 | 33 | 35 | 37 | 40 | 43 | 46 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /src/main/js/src/static/images/jsp.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | 12 | 26 | 27 | 30 | 33 | 35 | 37 | 40 | 43 | 46 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /src/main/webapp/static/js/index.f9d8e14098eb453538be.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack:///static/js/index.f9d8e14098eb453538be.js","webpack:///./src/polyfills/console.js","webpack:///./src/pages/index/index.js","webpack:///./src/polyfills/promise.js"],"names":["webpackJsonp","0","module","exports","__webpack_require__","Pp/C","method","noop","methods","length","console","window","U67u","__webpack_exports__","Object","defineProperty","value","log","cZNe","dist","dist_default","n","Promise","a","h2zT","i5Z1","__WEBPACK_IMPORTED_MODULE_0__styles_index_css__"],"mappings":"AAAAA,cAAc,IAERC,EACA,SAAUC,EAAQC,EAASC,GAEjCA,EAAoB,QACpBF,EAAOC,QAAUC,EAAoB,SAK/BC,OACA,SAAUH,EAAQC,ICZvB,WAYC,IAXA,GAAIG,GACAC,EAAO,aACPC,GACF,SAAU,QAAS,QAAS,QAAS,MAAO,SAAU,QACtD,YAAa,QAAS,iBAAkB,WAAY,OAAQ,MAC5D,eAAgB,UAAW,aAAc,QAAS,OAAQ,UAC1D,YAAa,QAAS,QAEpBC,EAASD,EAAQC,OACjBC,EAAWC,OAAOD,QAAUC,OAAOD,YAEhCD,KACLH,EAASE,EAAQC,GAGZC,EAAQJ,KACXI,EAAQJ,GAAUC,ODgBlBK,KACA,SAAUV,EAAQW,EAAqBT,GAE7C,YACAU,QAAOC,eAAeF,EAAqB,cAAgBG,OAAO,GACIZ,GAAoB,OEpC1FM,SAAQO,IAAI,gBF2CNC,KACA,SAAUhB,EAAQW,EAAqBT,GAE7C,YACAU,QAAOC,eAAeF,EAAqB,cAAgBG,OAAO,GAGlE,IAAIG,GAAOf,EAAoB,QAC3BgB,EAA4BhB,EAAoBiB,EAAEF,EGnDtDR,QAAOW,QAAUF,EAAAG,CH0DHnB,GAAoB,QAItBA,EAAoB,QAIvBA,EAAoB,QAIlBA,EAAoB,QAIdA,EAAoB,QAIjBA,EAAoB,QAIzBA,EAAoB,QAIpBA,EAAoB,QAItBA,EAAoB,QAIvBA,EAAoB,QAIjBA,EAAoB,QAInBA,EAAoB,QAItBA,EAAoB,SAqB1BoB,KACA,SAAUtB,EAAQC,KAMlBsB,KACA,SAAUvB,EAAQW,EAAqBT,GAE7C,YACqB,IAAIsB,GAAkDtB,EAAoB,OACZA,GAAoBiB,EAAEK,MAKtG","file":"static/js/index.f9d8e14098eb453538be.js","sourcesContent":["webpackJsonp([3],{\n\n/***/ 0:\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(\"cZNe\");\nmodule.exports = __webpack_require__(\"U67u\");\n\n\n/***/ }),\n\n/***/ \"Pp/C\":\n/***/ (function(module, exports) {\n\n(function () {\n var method;\n var noop = function noop() {};\n var methods = ['assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error', 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', 'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd', 'timeStamp', 'trace', 'warn'];\n var length = methods.length;\n var console = window.console = window.console || {};\n\n while (length--) {\n method = methods[length];\n\n // Only stub undefined methods.\n if (!console[method]) {\n console[method] = noop;\n }\n }\n})();\n\n/***/ }),\n\n/***/ \"U67u\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\nObject.defineProperty(__webpack_exports__, \"__esModule\", { value: true });\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__shares_page__ = __webpack_require__(\"i5Z1\");\n\n\nconsole.log('hello world');\n\n/***/ }),\n\n/***/ \"cZNe\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\nObject.defineProperty(__webpack_exports__, \"__esModule\", { value: true });\n\n// EXTERNAL MODULE: ./node_modules/nuo/dist/index.js\nvar dist = __webpack_require__(\"SbJX\");\nvar dist_default = /*#__PURE__*/__webpack_require__.n(dist);\n\n// CONCATENATED MODULE: ./src/polyfills/promise.js\n\n\nwindow.Promise = dist_default.a;\n// EXTERNAL MODULE: ./src/polyfills/console.js\nvar console = __webpack_require__(\"Pp/C\");\nvar console_default = /*#__PURE__*/__webpack_require__.n(console);\n\n// EXTERNAL MODULE: ./node_modules/core-js/es6/array.js\nvar array = __webpack_require__(\"cUYv\");\nvar array_default = /*#__PURE__*/__webpack_require__.n(array);\n\n// EXTERNAL MODULE: ./node_modules/core-js/fn/array/of.js\nvar of = __webpack_require__(\"PPkL\");\nvar of_default = /*#__PURE__*/__webpack_require__.n(of);\n\n// EXTERNAL MODULE: ./node_modules/core-js/fn/array/find.js\nvar find = __webpack_require__(\"0K64\");\nvar find_default = /*#__PURE__*/__webpack_require__.n(find);\n\n// EXTERNAL MODULE: ./node_modules/core-js/fn/array/find-index.js\nvar find_index = __webpack_require__(\"X8hh\");\nvar find_index_default = /*#__PURE__*/__webpack_require__.n(find_index);\n\n// EXTERNAL MODULE: ./node_modules/core-js/fn/object/assign.js\nvar object_assign = __webpack_require__(\"kLF+\");\nvar assign_default = /*#__PURE__*/__webpack_require__.n(object_assign);\n\n// EXTERNAL MODULE: ./node_modules/core-js/fn/array/includes.js\nvar includes = __webpack_require__(\"fB7P\");\nvar includes_default = /*#__PURE__*/__webpack_require__.n(includes);\n\n// EXTERNAL MODULE: ./node_modules/core-js/fn/array/iterator.js\nvar iterator = __webpack_require__(\"mBqO\");\nvar iterator_default = /*#__PURE__*/__webpack_require__.n(iterator);\n\n// EXTERNAL MODULE: ./node_modules/core-js/es6/string.js\nvar string = __webpack_require__(\"oFcf\");\nvar string_default = /*#__PURE__*/__webpack_require__.n(string);\n\n// EXTERNAL MODULE: ./node_modules/core-js/es6/map.js\nvar map = __webpack_require__(\"7N90\");\nvar map_default = /*#__PURE__*/__webpack_require__.n(map);\n\n// EXTERNAL MODULE: ./node_modules/core-js/es6/symbol.js\nvar symbol = __webpack_require__(\"wu3h\");\nvar symbol_default = /*#__PURE__*/__webpack_require__.n(symbol);\n\n// EXTERNAL MODULE: ./node_modules/regenerator-runtime/runtime.js\nvar runtime = __webpack_require__(\"SldL\");\nvar runtime_default = /*#__PURE__*/__webpack_require__.n(runtime);\n\n// EXTERNAL MODULE: ./node_modules/whatwg-fetch/fetch.js\nvar fetch = __webpack_require__(\"rplX\");\nvar fetch_default = /*#__PURE__*/__webpack_require__.n(fetch);\n\n// CONCATENATED MODULE: ./src/polyfills/index.js\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/***/ }),\n\n/***/ \"h2zT\":\n/***/ (function(module, exports) {\n\n// removed by extract-text-webpack-plugin\n\n/***/ }),\n\n/***/ \"i5Z1\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__styles_index_css__ = __webpack_require__(\"h2zT\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__styles_index_css___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0__styles_index_css__);\n\n\n/***/ })\n\n},[0]);\n\n\n// WEBPACK FOOTER //\n// static/js/index.f9d8e14098eb453538be.js","(function () {\n var method\n var noop = function () {}\n var methods = [\n 'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',\n 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',\n 'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',\n 'timeStamp', 'trace', 'warn'\n ]\n var length = methods.length\n var console = (window.console = window.console || {})\n\n while (length--) {\n method = methods[length]\n\n // Only stub undefined methods.\n if (!console[method]) {\n console[method] = noop\n }\n }\n}())\n\n\n\n// WEBPACK FOOTER //\n// ./src/polyfills/console.js","import '@/shares/page'\n\nconsole.log('hello world')\n\n\n\n// WEBPACK FOOTER //\n// ./src/pages/index/index.js","import Promise from 'nuo'\n\nwindow.Promise = Promise\n\n\n\n// WEBPACK FOOTER //\n// ./src/polyfills/promise.js"],"sourceRoot":""} -------------------------------------------------------------------------------- /src/main/webapp/static/js/contact.ae1113387e1befd7ff8b.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack:///static/js/contact.ae1113387e1befd7ff8b.js","webpack:///./src/polyfills/console.js","webpack:///./src/polyfills/promise.js"],"names":["webpackJsonp","2","module","exports","__webpack_require__","CNGw","__webpack_exports__","Object","defineProperty","value","__WEBPACK_IMPORTED_MODULE_1__index_css__","n","Pp/C","method","noop","methods","length","console","window","cZNe","dist","dist_default","Promise","a","h2zT","i5Z1","__WEBPACK_IMPORTED_MODULE_0__styles_index_css__","rv4b"],"mappings":"AAAAA,cAAc,IAERC,EACA,SAAUC,EAAQC,EAASC,GAEjCA,EAAoB,QACpBF,EAAOC,QAAUC,EAAoB,SAK/BC,KACA,SAAUH,EAAQI,EAAqBF,GAE7C,YACAG,QAAOC,eAAeF,EAAqB,cAAgBG,OAAO,GAC7C,IACIC,IAD6CN,EAAoB,QACtBA,EAAoB,QACZA,GAAoBO,EAAED,IAM5FE,OACA,SAAUV,EAAQC,ICzBvB,WAYC,IAXA,GAAIU,GACAC,EAAO,aACPC,GACF,SAAU,QAAS,QAAS,QAAS,MAAO,SAAU,QACtD,YAAa,QAAS,iBAAkB,WAAY,OAAQ,MAC5D,eAAgB,UAAW,aAAc,QAAS,OAAQ,UAC1D,YAAa,QAAS,QAEpBC,EAASD,EAAQC,OACjBC,EAAWC,OAAOD,QAAUC,OAAOD,YAEhCD,KACLH,EAASE,EAAQC,GAGZC,EAAQJ,KACXI,EAAQJ,GAAUC,OD6BlBK,KACA,SAAUjB,EAAQI,EAAqBF,GAE7C,YACAG,QAAOC,eAAeF,EAAqB,cAAgBG,OAAO,GAGlE,IAAIW,GAAOhB,EAAoB,QAC3BiB,EAA4BjB,EAAoBO,EAAES,EEpDtDF,QAAOI,QAAUD,EAAAE,CF2DHnB,GAAoB,QAItBA,EAAoB,QAIvBA,EAAoB,QAIlBA,EAAoB,QAIdA,EAAoB,QAIjBA,EAAoB,QAIzBA,EAAoB,QAIpBA,EAAoB,QAItBA,EAAoB,QAIvBA,EAAoB,QAIjBA,EAAoB,QAInBA,EAAoB,QAItBA,EAAoB,SAqB1BoB,KACA,SAAUtB,EAAQC,KAMlBsB,KACA,SAAUvB,EAAQI,EAAqBF,GAE7C,YACqB,IAAIsB,GAAkDtB,EAAoB,OACZA,GAAoBO,EAAEe,IAKnGC,KACA,SAAUzB,EAAQC,OAMrB","file":"static/js/contact.ae1113387e1befd7ff8b.js","sourcesContent":["webpackJsonp([2],{\n\n/***/ 2:\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(\"cZNe\");\nmodule.exports = __webpack_require__(\"CNGw\");\n\n\n/***/ }),\n\n/***/ \"CNGw\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\nObject.defineProperty(__webpack_exports__, \"__esModule\", { value: true });\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__shares_page__ = __webpack_require__(\"i5Z1\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__index_css__ = __webpack_require__(\"rv4b\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__index_css___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1__index_css__);\n\n\n\n/***/ }),\n\n/***/ \"Pp/C\":\n/***/ (function(module, exports) {\n\n(function () {\n var method;\n var noop = function noop() {};\n var methods = ['assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error', 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', 'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd', 'timeStamp', 'trace', 'warn'];\n var length = methods.length;\n var console = window.console = window.console || {};\n\n while (length--) {\n method = methods[length];\n\n // Only stub undefined methods.\n if (!console[method]) {\n console[method] = noop;\n }\n }\n})();\n\n/***/ }),\n\n/***/ \"cZNe\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\nObject.defineProperty(__webpack_exports__, \"__esModule\", { value: true });\n\n// EXTERNAL MODULE: ./node_modules/nuo/dist/index.js\nvar dist = __webpack_require__(\"SbJX\");\nvar dist_default = /*#__PURE__*/__webpack_require__.n(dist);\n\n// CONCATENATED MODULE: ./src/polyfills/promise.js\n\n\nwindow.Promise = dist_default.a;\n// EXTERNAL MODULE: ./src/polyfills/console.js\nvar console = __webpack_require__(\"Pp/C\");\nvar console_default = /*#__PURE__*/__webpack_require__.n(console);\n\n// EXTERNAL MODULE: ./node_modules/core-js/es6/array.js\nvar array = __webpack_require__(\"cUYv\");\nvar array_default = /*#__PURE__*/__webpack_require__.n(array);\n\n// EXTERNAL MODULE: ./node_modules/core-js/fn/array/of.js\nvar of = __webpack_require__(\"PPkL\");\nvar of_default = /*#__PURE__*/__webpack_require__.n(of);\n\n// EXTERNAL MODULE: ./node_modules/core-js/fn/array/find.js\nvar find = __webpack_require__(\"0K64\");\nvar find_default = /*#__PURE__*/__webpack_require__.n(find);\n\n// EXTERNAL MODULE: ./node_modules/core-js/fn/array/find-index.js\nvar find_index = __webpack_require__(\"X8hh\");\nvar find_index_default = /*#__PURE__*/__webpack_require__.n(find_index);\n\n// EXTERNAL MODULE: ./node_modules/core-js/fn/object/assign.js\nvar object_assign = __webpack_require__(\"kLF+\");\nvar assign_default = /*#__PURE__*/__webpack_require__.n(object_assign);\n\n// EXTERNAL MODULE: ./node_modules/core-js/fn/array/includes.js\nvar includes = __webpack_require__(\"fB7P\");\nvar includes_default = /*#__PURE__*/__webpack_require__.n(includes);\n\n// EXTERNAL MODULE: ./node_modules/core-js/fn/array/iterator.js\nvar iterator = __webpack_require__(\"mBqO\");\nvar iterator_default = /*#__PURE__*/__webpack_require__.n(iterator);\n\n// EXTERNAL MODULE: ./node_modules/core-js/es6/string.js\nvar string = __webpack_require__(\"oFcf\");\nvar string_default = /*#__PURE__*/__webpack_require__.n(string);\n\n// EXTERNAL MODULE: ./node_modules/core-js/es6/map.js\nvar map = __webpack_require__(\"7N90\");\nvar map_default = /*#__PURE__*/__webpack_require__.n(map);\n\n// EXTERNAL MODULE: ./node_modules/core-js/es6/symbol.js\nvar symbol = __webpack_require__(\"wu3h\");\nvar symbol_default = /*#__PURE__*/__webpack_require__.n(symbol);\n\n// EXTERNAL MODULE: ./node_modules/regenerator-runtime/runtime.js\nvar runtime = __webpack_require__(\"SldL\");\nvar runtime_default = /*#__PURE__*/__webpack_require__.n(runtime);\n\n// EXTERNAL MODULE: ./node_modules/whatwg-fetch/fetch.js\nvar fetch = __webpack_require__(\"rplX\");\nvar fetch_default = /*#__PURE__*/__webpack_require__.n(fetch);\n\n// CONCATENATED MODULE: ./src/polyfills/index.js\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/***/ }),\n\n/***/ \"h2zT\":\n/***/ (function(module, exports) {\n\n// removed by extract-text-webpack-plugin\n\n/***/ }),\n\n/***/ \"i5Z1\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__styles_index_css__ = __webpack_require__(\"h2zT\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__styles_index_css___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0__styles_index_css__);\n\n\n/***/ }),\n\n/***/ \"rv4b\":\n/***/ (function(module, exports) {\n\n// removed by extract-text-webpack-plugin\n\n/***/ })\n\n},[2]);\n\n\n// WEBPACK FOOTER //\n// static/js/contact.ae1113387e1befd7ff8b.js","(function () {\n var method\n var noop = function () {}\n var methods = [\n 'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',\n 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',\n 'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',\n 'timeStamp', 'trace', 'warn'\n ]\n var length = methods.length\n var console = (window.console = window.console || {})\n\n while (length--) {\n method = methods[length]\n\n // Only stub undefined methods.\n if (!console[method]) {\n console[method] = noop\n }\n }\n}())\n\n\n\n// WEBPACK FOOTER //\n// ./src/polyfills/console.js","import Promise from 'nuo'\n\nwindow.Promise = Promise\n\n\n\n// WEBPACK FOOTER //\n// ./src/polyfills/promise.js"],"sourceRoot":""} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

WJSP

2 | 3 | ## WEBPACK + JSP 构建多页应用 4 | 5 | ### 概述 6 | 传统的JSP页面应用无法有效的使用ES6语法特性,项目打包压缩困难,无法热更新。传统的单页应用在Tomcat等容器下无法进行服务端渲染到达SEO的效果。本项目工程很好融合的传统JSP页面服务端渲染的特点和单页应用开发特性且极易上手使用! 7 | 8 | ### 源码地址 9 | [源码地址](https://github.com/nqdy666/wjsp) 10 | 11 | ### Demos与文档 12 | [Demos与文档](http://wjsp.qjzd.net/) 13 | 14 | ### 特性 15 | * 多页应用 16 | * JSP嵌套 17 | * el表达式 18 | * 服务端渲染(SEO) 19 | * 热部署 20 | * js,css语法转换 21 | * eslint 22 | * 热更新 23 | * 支持Vue 24 | * 打包压缩 25 | * IE9+ 26 | 支持传统JSP开发所的所有功能;可以通过自定义webpack配置来实现对react的支持;通过引入vue-router和vuex某一个页面完成可以变成一个单页应用。 27 | 28 | 如果您想要支持IE8,那需要把webpack降级,因为webpack2+是不支持IE8的,以及尽量避免去使用不支持IE8的库,比如jquery2+,lodash4+, Vue等,祝您好运。 29 | 30 | ### 环境搭建 31 | 工欲善其事,必先利其器。 32 | 33 | * JDK1.7+ 34 | * IntelliJ IDEA,需要安装js相关插件和配置支持es6语法。 35 | * Maven3+ 36 | * Tomcat7+,端口默认请使用8080 37 | * Git bash 38 | * npm3+ 39 | * node7+ 40 | 41 | 如果您喜欢编辑js和css的时候用vscode也是没有问题,不过编写jsp和java还是推荐用idea。 42 | 43 | 以下总结环境配置的相关文章,可供参考 44 | [JDK下载地址](https://qjzd.net/topic/5a4e1ef4f918faeb40031460) 45 | [IntelliJ IDEA配置前端开发环境](https://qjzd.net/topic/5a4ee74ff918faeb40031461) 46 | [IntelliJ IDEA配置JAVA WEB的Tomcat环境](https://qjzd.net/topic/5a4eef92f918faeb40031462) 47 | [maven下载安装](https://qjzd.net/topic/5a4ef4f0f918faeb40031463) 48 | [Git Bash下载安装](https://qjzd.net/topic/5a4ef698f918faeb40031464) 49 | 50 | ### 目录说明 51 | ``` 52 | ├── pom.xml // maven配置文件 53 | ├── src 54 | | ├── main 55 | | | ├── filters 56 | | | | └── resources // java工程资源配置目录 57 | | | ├── java // java代码目录 58 | | | ├── js // 前端页面工程 59 | | | | ├── build // 编译相关以及webpack相关配置 60 | | | | | ├── build.js 61 | | | | | ├── check-versions.js 62 | | | | | ├── logo.png 63 | | | | | ├── utils.js 64 | | | | | ├── webpack.base.conf.js 65 | | | | | ├── webpack.dev.conf.js 66 | | | | | └── webpack.prod.conf.js 67 | | | | ├── config // 配置相关 68 | | | | | ├── dev.env.js 69 | | | | | ├── index.js 70 | | | | | ├── js-jsp-map.js // 配置入口js和jsp的映射 71 | | | | | └── prod.env.js 72 | | | | ├── package.json // npm配置 73 | | | | ├── src // web项目工程目录 74 | | | | | ├── pages // jsp页面,最终的jsp文件们会按照pages相对路径打包进webapp/WEB-INF/jsp目录下 75 | | | | | | ├── include // 共享的jsp页面,通过jsp:include引入 76 | | | | | | | ├── common_script.jsp 77 | | | | | | | ├── footer.jsp 78 | | | | | | | ├── header.jsp 79 | | | | | | | ├── init.jsp 80 | | | | | | | └── meta.jsp 81 | | | | | | ├── index // 页面1 82 | | | | | | | ├── index.js // 需要在在config/js-jsp-map.js配置与jsp的映射关系,这样编译后的js会加载jsp的body下。一般js与jsp在同一个目录下。 83 | | | | | | | └── index.jsp 84 | | | | | | └── start // 页面2 85 | | | | | | ├── dashboard.css 86 | | | | | | ├── index.js 87 | | | | | | └── index.jsp 88 | | | | | └── my-component.vue 支持VUE 89 | | | | ├── polyfills 兼容相关的代码 90 | | | | | ├── console.js 91 | | | | | ├── index.js 92 | | | | | └── promise.js 93 | | | | ├── static // 存在静态文件,最终这些文件会拷贝到webapp目录下 94 | | | | | ├── favicon.ico 95 | | | | | ├── images 96 | | | | | | ├── jsp.svg 97 | | | | | | └── webpack.svg 98 | | | | | ├── js 99 | | | | | | └── lib 100 | | | | | | └── jquery.min.js 101 | | | | | └── WEB-INF 102 | | | | | ├── tld 103 | | | | | └── web.xml 104 | | | | └── styles 105 | | | └── webapp // 该目录下的文件不用开发人员手动添加修改,在npm run dev或npm run build的时候自动生成。 106 | | └── test 107 | | └── java 108 | ``` 109 | src/main/js目录下的目录结构是在vue-cli的webpack模板的基础上修改的,如果您使用过该模板创建过项目,那么将很容易会上手。 110 | 111 | ### 开发 112 | `cd src/main/js` 113 | `npm run dev` 114 | 115 | 在idea中启动tomcat 116 | 117 | 在浏览器中打开`http://localhost:8081` 118 | 119 | 以下几点需要注意一下 120 | 121 | 首次启动项目,建议先`npm run dev`在启动tomcat。之后其中一个重启,另外一个可以不用重启。 122 | 默认情况下`npm run dev`跑在8081端口下,tomcat跑在8080端口下。最终在浏览器访问只需要访问8081的页面,8080页面没有必要。 123 | 开发模式下,js引入的css是动态引入的,页面会出现闪变的效果。不用担心,在发布后的环境中是不会出现的。 124 | 开发jsp页面的时候,热部署会有延时,具体参看JSP页面这一章节 125 | 开发jsp文件务必在pages目录下开发,切勿在webapp目录下开发。否则在切换到pages目录下开发或者打包后或,webapp下的jsp的文件会被覆盖,导致修改的内容丢失。 126 | 随着js-jsp-map.js中配置的的入口文件增加,webpack-dev-server的热更新会很慢,建议根据当前开发需要先临时注释掉一些暂未使用的入口文件,保留1至3个即可,会大大提高热更新时间。 127 | 128 | ### 打包发布 129 | `npm run build` 130 | 131 | webapp作为输出目录,static中文件会拷贝到输出目录,pages目录下的jsp文件会作为模板文件拷贝到webapp/WEB-INF/jsp目录下,与jsp关联的js入口会被合并压缩后引入到jsp文件的body中。jsp关联的css会被抽离出一个单个的css文件引入的jsp文件head中。 132 | 133 | 如果您打包后的应用的Application Context不是/, 比如是`/app`,即访问地址都是基于`http://localhost:8080/app`,那么打包的时候webpack的`publicPath`参数记得配置/app,且jsp页面中所有的地址都需要带上`${pageContext.request.contextPath}/`,在该项目框架中可以简写为`${ctx}/` 134 | 135 | ### JSP页面 136 | 传统的JSP是在`src/main/webapp`下开发,在这个项目框架下开发jsp文件是在`src/main/js/src/pages`下开发。虽然开发目录不一致,但依然拥有传统jsp开发所有的特性。 137 | 138 | * 模板嵌套,比如使用``或者`<%@include file=""%>` 139 | * el表达式,``, ``, ``等都可以使用 140 | * 嵌入Java代码 比如使用`<% out.println("hello world"); %>` 141 | * 支持热部署。配置好启动tomcat相关参数。在修改完jsp保存文件后,约10秒后刷新页面就可以看到页面的变化。如果等不及10秒或者页面一直不刷新,可以先点击idea菜单`File->Syncronize>`同步文件(快捷键`Ctrl+Alt+Y`),然后在点击Run的左侧第三个按钮后选择`Update classes and resources`手动更新,之后就刷新页面就可以看到最新出的页面。 142 | 实际在`npm run dev`的时候,pages目录下的jsp会作为htmlWebpackPlugin插件的模板文件,每次修改pages下的文件都会被输出到`webapp/WEB-INF/jsp`下的相对目录。需要了解具体原理,请前往核心章节 143 | 144 | ### 自定义标签库 145 | 除了标准的c, fmt, fn标签库外,您也可以自定义标签库。 146 | 147 | * 首先在static/WEB-INF/tld新建一个tld,比如elftld 148 | * 然后jsp页面引入,`<%@ taglib prefix="elf" uri="/WEB-INF/tld/elfunc.tld" %>` 149 | 150 | 注意的是,在jsp页面的地址必须以/WEB-INF/开头,而实际开发jsp的路径是在`js/src/pages`目录下,导致idea无法正常解析pages目录下jsp中tld文件路径,在使用自定义标签的时候也无法自动补全。不过可以正常运行,实际开发过程影响不大。如果您有更好的解决方案,请与我们联系。 151 | 152 | ### 语法转换 153 | 因为了使用了webpack作为打包工具,您可以轻松对js和css进行语法转换,目前支持: 154 | 155 | * es6, stage-2 156 | * postcss 157 | * less, sass, scss 需要额外装对应的loader即可支持 158 | 159 | ### 热更新 160 | 在开发单页应用的过程中,有一个很棒的特性就是热更新,修改了js文件,页面实时就会触发更新。 161 | 在此项目框架下,您依然可以享受到热更新带来的喜悦,在您修改js和css的时候,页面都会实时触发更新。 162 | 163 | ### VUE 164 | 该项目已经默认支持Vue。这一章节也是用VUE编写的,你可以尽情的享受VUE带来的编码的快乐。 165 | 166 | * 您可以给idea添加vue.js插件,这样也可以直接使用.vue文件。 167 | * js和css的语法转换在.vue文件中同样适用。 168 | 169 | ### 核心 170 | 该项目融合了webpack和jsp两者的特性实现了多页应用,这很酷。那到底是如何实现的呢。这里我们从搭建项目遇到的问题来讲讲最核心的几个问题是如何解决的。 171 | 172 | ##### HtmlWebpackPlugin 173 | 使用webpack实现多页应用,很容易联想到配置多个entry入口,每一个entry对应一个`HtmlWebpackPlugin`。jsp文件作为`HtmlWebpackPlugin`的模板文件,在entry的js在打包之后会插入到body下。该项目也是按照这样的搭建的。 174 | 这里有几点需要注意 175 | * HtmlWebpackPlugin解析jsp文件需要对应的loader,需要在webpack中配置`{ test: /\.jsp$/, loader: 'raw-loader' }`,这里使用`raw-loader`进行纯文本拷贝。如果您有更适合jsp的loader,那么您可以赋予jsp文件特多的特性。 176 | * 因为jsp可以被嵌套,这些被嵌套的jsp,并不是入口的jsp。所有只有是入口的jsp在配合HtmlWebpackPlugin插件的会额外添加{inject: 'body'}参数 177 | * 那如何规定哪些jsp是入口文件呢?我们是通过配置来约定entry的js与jsp的关联关系,配置文件在`config/js-jsp-map.js`中。 178 | 179 | ### proxy反代 180 | tomcat是跑在8080端口下的,webpack-dev-server是跑在8081端口下的,是两个不同应用。那岂不是开发jsp要在tomcat下编写调试,开发js在webpack-dev-server调试。这样的话岂不是很麻烦。 181 | 182 | 庆幸的webpack-dev-server有一个proxy参数,我们利用proxy把访问webpack-dev-server的请求都反代到8080下。这样实际开发过程中浏览器只要打开8081端口页面就可以。这样就做到兼顾jsp服务端渲染的功能,以及webpack语法转换,热更新的功能。tomcat只有在必要的时候重启一下就好。 183 | 这里有几点需要注意 184 | * `npm run dev`和启动tomcat并没有顺序要求,不过在浏览器访问8081前需要把这两个服务都启动起来。 185 | * 当涉及到jsp文件有新增删除,或者static目录下的文件有新增编辑删除时,需要重新`npm run dev`和重启tomcat。记住一点,如果有文件新增和删除,最好都把这两个服务都重启一下肯定是没有问题的。 186 | 187 | ### WriteFilePlugin 188 | 我们知道webpack-dev-server是使用内存中的文件系统。而jsp页面最终是要发布到tomcat的,内存中的jsp文件并不能被idea监听,这样即使最终输出的jsp发生改变也无法被deploy到tomcat。 189 | 庆幸我们找到了一个webpack的插件WriteFilePlugin,它能强制把webpack-dev-server程序的输出的文件写到磁盘文件系统上。 190 | 这里有几点需要注意 191 | * 虽然通过WriteFilePlugin的jsp文件输出到磁盘上了,但是因为不是通过idea直接修改,idea还是无法立刻同步这些文件。idea同步并发布jsp文件会有10s的延迟。如果等不及10秒或者页面一直不刷新,可以先点击idea菜单File->Syncronize>同步文件(快捷键Ctrl+Alt+Y),然后在点击Run的左侧第三个按钮后选择Update classes and resources手动更新,之后就刷新页面就可以看到最新出的页面。 192 | 193 | ### 结语 194 | 这个思路其实不仅适用tomcat下的jsp多页应用,同样也是适用node作为服务器的多页应用。Enjoy it! -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | net.qjzd 5 | wjsp 6 | war 7 | 1.0.0 8 | 9 | dtu Maven Webapp 10 | http://maven.apache.org 11 | 12 | 13 | UTF-8 14 | 4.0.3.RELEASE 15 | yyyyMMdd 16 | 17 | 18 | 19 | 20 | 21 | javax.servlet 22 | javax.servlet-api 23 | 3.1.0 24 | provided 25 | 26 | 27 | junit 28 | junit 29 | 4.10 30 | test 31 | 32 | 33 | org.springframework 34 | spring-test 35 | ${org.springframework.version} 36 | test 37 | 38 | 39 | 40 | org.mockito 41 | mockito-all 42 | 1.10.19 43 | test 44 | 45 | 46 | commons-beanutils 47 | commons-beanutils 48 | 1.8.3 49 | 50 | 51 | commons-chain 52 | commons-chain 53 | 1.2 54 | 55 | 56 | commons-codec 57 | commons-codec 58 | 1.6 59 | 60 | 61 | commons-collections 62 | commons-collections 63 | 3.2 64 | 65 | 66 | commons-digester 67 | commons-digester 68 | 1.8 69 | 70 | 71 | commons-fileupload 72 | commons-fileupload 73 | 1.2.2 74 | 75 | 76 | commons-io 77 | commons-io 78 | 2.1 79 | 80 | 81 | org.apache.commons 82 | commons-lang3 83 | 3.3 84 | 85 | 86 | commons-logging 87 | commons-logging 88 | 1.1 89 | 90 | 91 | javax.servlet 92 | servlet-api 93 | 94 | 95 | 96 | 97 | org.apache.commons 98 | commons-pool2 99 | 2.4.2 100 | 101 | 102 | ca.juliusdavies 103 | not-yet-commons-ssl 104 | 0.3.11 105 | 106 | 107 | 108 | dom4j 109 | dom4j 110 | 1.6.1 111 | 112 | 113 | 114 | com.alibaba 115 | fastjson 116 | 1.2.7 117 | 118 | 119 | org.jdom 120 | jdom 121 | 1.1.3 122 | 123 | 124 | redis.clients 125 | jedis 126 | 2.7.3 127 | 128 | 129 | log4j 130 | log4j 131 | 1.2.17 132 | 133 | 134 | 135 | org.springframework 136 | spring-aop 137 | ${org.springframework.version} 138 | 139 | 140 | org.springframework 141 | spring-beans 142 | ${org.springframework.version} 143 | 144 | 145 | org.springframework 146 | spring-context 147 | ${org.springframework.version} 148 | 149 | 150 | org.springframework 151 | spring-context-support 152 | ${org.springframework.version} 153 | 154 | 155 | org.springframework 156 | spring-core 157 | ${org.springframework.version} 158 | 159 | 160 | org.springframework 161 | spring-expression 162 | ${org.springframework.version} 163 | 164 | 165 | org.springframework 166 | spring-jdbc 167 | ${org.springframework.version} 168 | 169 | 170 | org.springframework 171 | spring-orm 172 | ${org.springframework.version} 173 | 174 | 175 | org.springframework 176 | spring-oxm 177 | ${org.springframework.version} 178 | 179 | 180 | org.springframework 181 | spring-tx 182 | ${org.springframework.version} 183 | 184 | 185 | org.springframework 186 | spring-web 187 | ${org.springframework.version} 188 | 189 | 190 | org.springframework 191 | spring-webmvc 192 | ${org.springframework.version} 193 | 194 | 195 | org.springframework.data 196 | spring-data-redis 197 | 1.5.2.RELEASE 198 | 199 | 200 | org.springframework.session 201 | spring-session 202 | 1.0.2.RELEASE 203 | 204 | 205 | 206 | taglibs 207 | standard 208 | 1.1.2 209 | 210 | 211 | 212 | jstl 213 | jstl 214 | 1.2 215 | 216 | 217 | 218 | commons-httpclient 219 | commons-httpclient 220 | 3.0.1 221 | 222 | 223 | 224 | 225 | com.fasterxml.jackson.core 226 | jackson-databind 227 | 2.6.1 228 | 229 | 230 | 231 | c3p0 232 | c3p0 233 | 0.9.1.2 234 | 235 | 236 | 237 | mysql 238 | mysql-connector-java 239 | 5.1.17 240 | 241 | 242 | 243 | com.auth0 244 | java-jwt 245 | 3.2.0 246 | 247 | 248 | 249 | 250 | joda-time 251 | joda-time 252 | 2.8.2 253 | 254 | 255 | 256 | 257 | org.projectlombok 258 | lombok 259 | 1.14.8 260 | 261 | 262 | 263 | 264 | development 265 | 266 | development 267 | 268 | 269 | true 270 | 271 | 272 | 273 | product 274 | 275 | product 276 | 277 | 278 | 279 | 280 | 281 | 282 | org.apache.maven.plugins 283 | maven-compiler-plugin 284 | 3.1 285 | 286 | 1.7 287 | 1.7 288 | 289 | 290 | 291 | org.apache.tomcat.maven 292 | tomcat7-maven-plugin 293 | 2.2 294 | 295 | 296 | org.apache.maven.plugins 297 | maven-resources-plugin 298 | 2.6 299 | 300 | false 301 | 302 | 303 | 304 | org.apache.maven.plugins 305 | maven-war-plugin 306 | 2.6 307 | 308 | ${project.artifactId}-${project.version}-${maven.build.timestamp}-${env} 309 | 310 | 311 | 312 | org.apache.maven.plugins 313 | maven-release-plugin 314 | 2.5.2 315 | 316 | V@{project.version} 317 | 318 | 319 | 320 | 321 | 322 | src/main/resources/${env} 323 | true 324 | 325 | 326 | 327 | 328 | 329 | -------------------------------------------------------------------------------- /src/main/js/src/pages/start/index.jsp: -------------------------------------------------------------------------------- 1 | <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" isELIgnored="false" %> 2 | <%@include file="../include/init.jsp"%> 3 | 4 | 5 | 6 | WEBPACK-JSP 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 | 38 |
39 |
40 |
41 |

介绍

42 |

传统的JSP页面应用无法有效的使用ES6语法特性,项目打包压缩困难,无法热更新。传统的单页应用在Tomcat等容器下无法进行服务端渲染从而达到SEO的效果。本项目工程很好融合的传统JSP页面服务端渲染的特点和单页应用开发特性且极易上手使用!

43 |

特性

44 |
    45 |
  • 多页应用
  • 46 |
  • JSP嵌套
  • 47 |
  • el表达式
  • 48 |
  • 服务端渲染(SEO)
  • 49 |
  • 热部署
  • 50 |
  • js,css语法转换
  • 51 |
  • eslint
  • 52 |
  • 热更新
  • 53 |
  • 支持Vue
  • 54 |
  • 打包压缩
  • 55 |
  • IE9+
  • 56 |
57 |

支持传统JSP开发所的所有功能;可以通过自定义webpack配置来实现对react的支持;通过引入vue-router和vuex某一个页面完成可以变成一个单页应用。

58 |

如果您想要支持IE8,那需要把webpack降级,因为webpack2+是不支持IE8的,以及尽量避免去使用不支持IE8的库,比如jquery2+,lodash4+, Vue等,祝您好运。

59 |
60 |
61 |

环境搭建

62 |

工欲善其事,必先利其器。

63 |
    64 |
  • JDK1.7+
  • 65 |
  • IntelliJ IDEA,需要安装js相关插件和配置支持es6语法。
  • 66 |
  • Maven3+
  • 67 |
  • Tomcat7+,端口默认请使用8080
  • 68 |
  • Git bash
  • 69 |
  • npm3+
  • 70 |
  • node7+
  • 71 |
72 |

如果您喜欢编辑js和css的时候用vscode也是没有问题,不过编写jsp和java还是推荐用idea。

73 |

以下总结环境配置的相关文章,可供参考

74 |
  • JDK下载地址
  • 75 |
  • IntelliJ IDEA配置前端开发环境
  • 76 |
  • IntelliJ IDEA配置JAVA WEB的Tomcat环境
  • 77 |
  • maven下载安装
  • 78 |
  • Git Bash下载安装
  • 79 |
    80 |
    81 |

    目录说明

    82 |
     83 | ├── pom.xml   // maven配置文件
     84 | ├── src
     85 | |  ├── main
     86 | |  |  ├── filters
     87 | |  |  |  └── resources // java工程资源配置目录
     88 | |  |  ├── java // java代码目录
     89 | |  |  ├── js // 前端页面工程
     90 | |  |  |  ├── build  // 编译相关以及webpack相关配置
     91 | |  |  |  |  ├── build.js
     92 | |  |  |  |  ├── check-versions.js
     93 | |  |  |  |  ├── logo.png
     94 | |  |  |  |  ├── utils.js
     95 | |  |  |  |  ├── webpack.base.conf.js
     96 | |  |  |  |  ├── webpack.dev.conf.js
     97 | |  |  |  |  └── webpack.prod.conf.js
     98 | |  |  |  ├── config // 配置相关
     99 | |  |  |  |  ├── dev.env.js
    100 | |  |  |  |  ├── index.js
    101 | |  |  |  |  ├── js-jsp-map.js // 配置入口js和jsp的映射
    102 | |  |  |  |  └── prod.env.js
    103 | |  |  |  ├── package.json // npm配置
    104 | |  |  |  ├── src // web项目工程目录
    105 | |  |  |  |  ├── pages // jsp页面,最终的jsp文件们会按照pages相对路径打包进webapp/WEB-INF/jsp目录下
    106 | |  |  |  |  |  ├── include // 共享的jsp页面,通过jsp:include引入
    107 | |  |  |  |  |  |  ├── common_script.jsp
    108 | |  |  |  |  |  |  ├── footer.jsp
    109 | |  |  |  |  |  |  ├── header.jsp
    110 | |  |  |  |  |  |  ├── init.jsp
    111 | |  |  |  |  |  |  └── meta.jsp
    112 | |  |  |  |  |  ├── index // 页面1
    113 | |  |  |  |  |  |  ├── index.js // 需要在在config/js-jsp-map.js配置与jsp的映射关系,这样编译后的js会加载jsp的body下。一般js与jsp在同一个目录下。
    114 | |  |  |  |  |  |  └── index.jsp
    115 | |  |  |  |  |  └── start // 页面2
    116 | |  |  |  |  |     ├── dashboard.css
    117 | |  |  |  |  |     ├── index.js
    118 | |  |  |  |  |     └── index.jsp
    119 | |  |  |     |     └── my-component.vue 支持VUE
    120 | |  |  |     ├── polyfills 兼容相关的代码
    121 | |  |  |     |  ├── console.js
    122 | |  |  |     |  ├── index.js
    123 | |  |  |     |  └── promise.js
    124 | |  |  |     ├── static // 存在静态文件,最终这些文件会拷贝到webapp目录下
    125 | |  |  |     |  ├── favicon.ico
    126 | |  |  |     |  ├── images
    127 | |  |  |     |  |  ├── jsp.svg
    128 | |  |  |     |  |  └── webpack.svg
    129 | |  |  |     |  ├── js
    130 | |  |  |     |  |  └── lib
    131 | |  |  |     |  |     └── jquery.min.js
    132 | |  |  |     |  └── WEB-INF
    133 | |  |  |     |     ├── tld
    134 | |  |  |     |     └── web.xml
    135 | |  |  |     └── styles
    136 | |  |  └── webapp // 该目录下的文件不用开发人员手动添加修改,在npm run dev或npm run build的时候自动生成。
    137 | |  └── test
    138 | |     └── java
    139 |       
    140 |

    src/main/js目录下的目录结构是在vue-cli的webpack模板的基础上修改的,如果您使用过该模板创建过项目,那么将很容易会上手。

    141 |
    142 |
    143 |

    开发

    144 |

    cd src/main/js

    145 |

    npm run dev

    146 |

    在idea中启动tomcat

    147 |

    在浏览器中打开http://localhost:8081

    148 |

    以下几点需要注意一下

    149 |
      150 |
    • 首次启动项目,建议先npm run dev在启动tomcat。之后其中一个重启,另外一个可以不用重启。
    • 151 |
    • 默认情况下npm run dev跑在8081端口下,tomcat跑在8080端口下。最终在浏览器访问只需要访问8081的页面,8080页面没有必要。
    • 152 |
    • 开发模式下,js引入的css是动态引入的,页面会出现闪变的效果。不用担心,在发布后的环境中是不会出现的。
    • 153 |
    • 开发jsp页面的时候,热部署会有延时,具体参看JSP页面这一章节
    • 154 |
    • 开发jsp文件务必在pages目录下开发,切勿在webapp目录下开发。否则在切换到pages目录下开发或者打包后或,webapp下的jsp的文件会被覆盖,导致修改的内容丢失。
    • 155 |
    • 随着js-jsp-map.js中配置的的入口文件增加,webpack-dev-server的热更新会很慢,建议根据当前开发需要先临时注释掉一些暂未使用的入口文件,保留1至3个即可,会大大提高热更新时间。
    • 156 |
    157 |
    158 |
    159 |

    打包发布

    160 |

    npm run build

    161 |

    webapp作为输出目录,static中文件会拷贝到输出目录,pages目录下的jsp文件会作为模板文件拷贝到webapp/WEB-INF/jsp目录下,与jsp关联的js入口会被合并压缩后引入到jsp文件的body中。jsp关联的css会被抽离出一个单个的css文件引入的jsp文件head中。

    162 |

    以下几点需要注意一下

    163 |
      164 |
    • 如果您打包后的应用的Application Context不是/, 比如是/app,即访问地址都是基于http://localhost:8080/app,那么打包的时候webpack的publicPath参数记得配置/app,且jsp页面中所有的地址都需要带上${'$'}{pageContext.request.contextPath}/,在该项目框架中可以简写为${'$'}{ctx}/
    • 165 |
    • 如果您在打包后发现某些文件无法访问,请检查一下是否在tomcat环境下是否限制了某些文件类型的访问,比如检查一下web.xml中的相关配置。
    • 166 |
    167 |
    168 |
    169 |

    JSP页面

    170 |

    传统的JSP是在src/main/webapp下开发,在这个项目框架下开发jsp文件是在src/main/js/src/pages下开发。虽然开发目录不一致,但依然拥有传统jsp开发所有的特性。

    171 |
      172 |
    • 模板嵌套,比如使用${fn:escapeXml("")}或者<%@include file=""%>
    • 173 |
    • el表达式,${fn:escapeXml(", 等都可以使用
    • 174 |
    • 嵌入Java代码 比如使用<% out.println("hello world"); %>
    • 175 |
    • 支持热部署。配置好启动tomcat相关参数。在修改完jsp保存文件后,约10秒后刷新页面就可以看到页面的变化。如果等不及10秒或者页面一直不刷新,可以先点击idea菜单File->Syncronize>同步文件(快捷键Ctrl+Alt+Y),然后在点击Run的左侧第三个按钮后选择Update classes and resources手动更新,之后就刷新页面就可以看到最新出的页面。
    • 176 |
    177 |

    实际在npm run dev的时候,pages目录下的jsp会作为htmlWebpackPlugin插件的模板文件,每次修改pages下的文件都会被输出到webapp/WEB-INF/jsp下的相对目录。需要了解具体原理,请前往核心章节

    178 |
    179 |
    180 |

    自定义标签库

    181 |

    除了标准的c, fmt, fn标签库外,您也可以自定义标签库。

    182 |
      183 |
    • 首先在static/WEB-INF/tld新建一个tld,比如elftld
    • 184 |
    • 然后jsp页面引入,<%@ taglib prefix="elf" uri="/WEB-INF/tld/elfunc.tld" %>
    • 185 |
    186 |

    注意的是,在jsp页面的地址必须以/WEB-INF/开头,而实际开发jsp的路径是在js/src/pages目录下,导致idea无法正常解析pages目录下jsp中tld文件路径,在使用自定义标签的时候也无法自动补全。不过可以正常运行,实际开发过程影响不大。如果您有更好的解决方案,请与我们联系。

    187 |
    188 |
    189 |

    语法转换

    190 |

    因为了使用了webpack作为打包工具,您可以轻松对js和css进行语法转换,目前支持:

    191 |
      192 |
    • es6, stage-2
    • 193 |
    • postcss
    • 194 |
    • less, sass, scss 需要额外装对应的loader即可支持
    • 195 |
    196 |
    197 |
    198 |

    热更新

    199 |

    在开发单页应用的过程中,有一个很棒的特性就是热更新,修改了js文件,页面实时就会触发更新。

    200 |

    在此项目框架下,您依然可以享受到热更新带来的喜悦,在您修改js和css的时候,页面都会实时触发更新。

    201 |
    202 |
    203 |

    VUE

    204 |
    205 | 206 |
    207 |
    208 |
    209 |

    核心

    210 |

    该项目融合了webpack和jsp两者的特性实现了多页应用,这很酷。那到底是如何实现的呢。这里我们从搭建项目遇到的问题来讲讲最核心的几个问题是如何解决的。

    211 |

    HtmlWebpackPlugin

    212 |

    使用webpack实现多页应用,很容易联想到配置多个entry入口,每一个entry对应一个HtmlWebpackPlugin。jsp文件作为HtmlWebpackPlugin的模板文件,在entry的js在打包之后会插入到body下。该项目也是按照这样的搭建的。

    213 |

    这里有几点需要注意

    214 |
      215 |
    • HtmlWebpackPlugin解析jsp文件需要对应的loader,需要在webpack中配置{ test: /\.jsp$/, loader: 'raw-loader' },这里使用raw-loader进行纯文本拷贝。如果您有更适合jsp的loader,那么您可以赋予jsp文件特多的特性。
    • 216 |
    • 因为jsp可以被嵌套,这些被嵌套的jsp,并不是入口的jsp。所有只有是入口的jsp在配合HtmlWebpackPlugin插件的会额外添加{inject: 'body'}参数
    • 217 |
    • 那如何规定哪些jsp是入口文件呢?我们是通过配置来约定entry的js与jsp的关联关系,配置文件在config/js-jsp-map.js中。
    • 218 |
    219 |

    proxy反代

    220 |

    tomcat是跑在8080端口下的,webpack-dev-server是跑在8081端口下的,是两个不同应用。那岂不是开发jsp要在tomcat下编写调试,开发js在webpack-dev-server调试。这样的话岂不是很麻烦。

    221 |

    庆幸的webpack-dev-server有一个proxy参数,我们利用proxy把访问webpack-dev-server的请求都反代到8080下。这样实际开发过程中浏览器只要打开8081端口页面就可以。这样就做到兼顾jsp服务端渲染的功能,以及webpack语法转换,热更新的功能。tomcat只有在必要的时候重启一下就好。

    222 |

    这里有几点需要注意

    223 |
      224 |
    • npm run dev和启动tomcat并没有顺序要求,不过在浏览器访问8081前需要把这两个服务都启动起来。
    • 225 |
    • 当涉及到jsp文件有新增删除,或者static目录下的文件有新增编辑删除时,需要重新npm run dev和重启tomcat。记住一点,如果有文件新增和删除,最好都把这两个服务都重启一下肯定是没有问题的。
    • 226 |
    227 |

    WriteFilePlugin

    228 |

    我们知道webpack-dev-server是使用内存中的文件系统。而jsp页面最终是要发布到tomcat的,内存中的jsp文件并不能被idea监听,这样即使最终输出的jsp发生改变也无法被deploy到tomcat。

    229 |

    庆幸我们找到了一个webpack的插件WriteFilePlugin,它能强制把webpack-dev-server程序的输出的文件写到磁盘文件系统上。

    230 |

    这里有几点需要注意

    231 |
      232 |
    • 虽然通过WriteFilePlugin的jsp文件输出到磁盘上了,但是因为不是通过idea直接修改,idea还是无法立刻同步这些文件。idea同步并发布jsp文件会有10s的延迟。如果等不及10秒或者页面一直不刷新,可以先点击idea菜单File->Syncronize>同步文件(快捷键Ctrl+Alt+Y),然后在点击Run的左侧第三个按钮后选择Update classes and resources手动更新,之后就刷新页面就可以看到最新出的页面。
    • 233 |
    234 |

    结语

    235 |

    这个思路其实不仅适用tomcat下的jsp多页应用,同样也是适用node作为服务器的多页应用。Enjoy it!

    236 |
    237 |
    238 |
    239 | 240 | 241 | 242 | 243 | 244 | 245 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/jsp/start/index.jsp: -------------------------------------------------------------------------------- 1 | <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" isELIgnored="false" %> 2 | <%@include file="../include/init.jsp"%> 3 | 4 | 5 | 6 | WEBPACK-JSP 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
    16 |
    17 | 38 |
    39 |
    40 |
    41 |

    介绍

    42 |

    传统的JSP页面应用无法有效的使用ES6语法特性,项目打包压缩困难,无法热更新。传统的单页应用在Tomcat等容器下无法进行服务端渲染从而达到SEO的效果。本项目工程很好融合的传统JSP页面服务端渲染的特点和单页应用开发特性且极易上手使用!

    43 |

    特性

    44 |
      45 |
    • 多页应用
    • 46 |
    • JSP嵌套
    • 47 |
    • el表达式
    • 48 |
    • 服务端渲染(SEO)
    • 49 |
    • 热部署
    • 50 |
    • js,css语法转换
    • 51 |
    • eslint
    • 52 |
    • 热更新
    • 53 |
    • 支持Vue
    • 54 |
    • 打包压缩
    • 55 |
    • IE9+
    • 56 |
    57 |

    支持传统JSP开发所的所有功能;可以通过自定义webpack配置来实现对react的支持;通过引入vue-router和vuex某一个页面完成可以变成一个单页应用。

    58 |

    如果您想要支持IE8,那需要把webpack降级,因为webpack2+是不支持IE8的,以及尽量避免去使用不支持IE8的库,比如jquery2+,lodash4+, Vue等,祝您好运。

    59 |
    60 |
    61 |

    环境搭建

    62 |

    工欲善其事,必先利其器。

    63 |
      64 |
    • JDK1.7+
    • 65 |
    • IntelliJ IDEA,需要安装js相关插件和配置支持es6语法。
    • 66 |
    • Maven3+
    • 67 |
    • Tomcat7+,端口默认请使用8080
    • 68 |
    • Git bash
    • 69 |
    • npm3+
    • 70 |
    • node7+
    • 71 |
    72 |

    如果您喜欢编辑js和css的时候用vscode也是没有问题,不过编写jsp和java还是推荐用idea。

    73 |

    以下总结环境配置的相关文章,可供参考

    74 |
  • JDK下载地址
  • 75 |
  • IntelliJ IDEA配置前端开发环境
  • 76 |
  • IntelliJ IDEA配置JAVA WEB的Tomcat环境
  • 77 |
  • maven下载安装
  • 78 |
  • Git Bash下载安装
  • 79 |
    80 |
    81 |

    目录说明

    82 |
     83 | ├── pom.xml   // maven配置文件
     84 | ├── src
     85 | |  ├── main
     86 | |  |  ├── filters
     87 | |  |  |  └── resources // java工程资源配置目录
     88 | |  |  ├── java // java代码目录
     89 | |  |  ├── js // 前端页面工程
     90 | |  |  |  ├── build  // 编译相关以及webpack相关配置
     91 | |  |  |  |  ├── build.js
     92 | |  |  |  |  ├── check-versions.js
     93 | |  |  |  |  ├── logo.png
     94 | |  |  |  |  ├── utils.js
     95 | |  |  |  |  ├── webpack.base.conf.js
     96 | |  |  |  |  ├── webpack.dev.conf.js
     97 | |  |  |  |  └── webpack.prod.conf.js
     98 | |  |  |  ├── config // 配置相关
     99 | |  |  |  |  ├── dev.env.js
    100 | |  |  |  |  ├── index.js
    101 | |  |  |  |  ├── js-jsp-map.js // 配置入口js和jsp的映射
    102 | |  |  |  |  └── prod.env.js
    103 | |  |  |  ├── package.json // npm配置
    104 | |  |  |  ├── src // web项目工程目录
    105 | |  |  |  |  ├── pages // jsp页面,最终的jsp文件们会按照pages相对路径打包进webapp/WEB-INF/jsp目录下
    106 | |  |  |  |  |  ├── include // 共享的jsp页面,通过jsp:include引入
    107 | |  |  |  |  |  |  ├── common_script.jsp
    108 | |  |  |  |  |  |  ├── footer.jsp
    109 | |  |  |  |  |  |  ├── header.jsp
    110 | |  |  |  |  |  |  ├── init.jsp
    111 | |  |  |  |  |  |  └── meta.jsp
    112 | |  |  |  |  |  ├── index // 页面1
    113 | |  |  |  |  |  |  ├── index.js // 需要在在config/js-jsp-map.js配置与jsp的映射关系,这样编译后的js会加载jsp的body下。一般js与jsp在同一个目录下。
    114 | |  |  |  |  |  |  └── index.jsp
    115 | |  |  |  |  |  └── start // 页面2
    116 | |  |  |  |  |     ├── dashboard.css
    117 | |  |  |  |  |     ├── index.js
    118 | |  |  |  |  |     └── index.jsp
    119 | |  |  |     |     └── my-component.vue 支持VUE
    120 | |  |  |     ├── polyfills 兼容相关的代码
    121 | |  |  |     |  ├── console.js
    122 | |  |  |     |  ├── index.js
    123 | |  |  |     |  └── promise.js
    124 | |  |  |     ├── static // 存在静态文件,最终这些文件会拷贝到webapp目录下
    125 | |  |  |     |  ├── favicon.ico
    126 | |  |  |     |  ├── images
    127 | |  |  |     |  |  ├── jsp.svg
    128 | |  |  |     |  |  └── webpack.svg
    129 | |  |  |     |  ├── js
    130 | |  |  |     |  |  └── lib
    131 | |  |  |     |  |     └── jquery.min.js
    132 | |  |  |     |  └── WEB-INF
    133 | |  |  |     |     ├── tld
    134 | |  |  |     |     └── web.xml
    135 | |  |  |     └── styles
    136 | |  |  └── webapp // 该目录下的文件不用开发人员手动添加修改,在npm run dev或npm run build的时候自动生成。
    137 | |  └── test
    138 | |     └── java
    139 |       
    140 |

    src/main/js目录下的目录结构是在vue-cli的webpack模板的基础上修改的,如果您使用过该模板创建过项目,那么将很容易会上手。

    141 |
    142 |
    143 |

    开发

    144 |

    cd src/main/js

    145 |

    npm run dev

    146 |

    在idea中启动tomcat

    147 |

    在浏览器中打开http://localhost:8081

    148 |

    以下几点需要注意一下

    149 |
      150 |
    • 首次启动项目,建议先npm run dev在启动tomcat。之后其中一个重启,另外一个可以不用重启。
    • 151 |
    • 默认情况下npm run dev跑在8081端口下,tomcat跑在8080端口下。最终在浏览器访问只需要访问8081的页面,8080页面没有必要。
    • 152 |
    • 开发模式下,js引入的css是动态引入的,页面会出现闪变的效果。不用担心,在发布后的环境中是不会出现的。
    • 153 |
    • 开发jsp页面的时候,热部署会有延时,具体参看JSP页面这一章节
    • 154 |
    • 开发jsp文件务必在pages目录下开发,切勿在webapp目录下开发。否则在切换到pages目录下开发或者打包后或,webapp下的jsp的文件会被覆盖,导致修改的内容丢失。
    • 155 |
    • 随着js-jsp-map.js中配置的的入口文件增加,webpack-dev-server的热更新会很慢,建议根据当前开发需要先临时注释掉一些暂未使用的入口文件,保留1至3个即可,会大大提高热更新时间。
    • 156 |
    157 |
    158 |
    159 |

    打包发布

    160 |

    npm run build

    161 |

    webapp作为输出目录,static中文件会拷贝到输出目录,pages目录下的jsp文件会作为模板文件拷贝到webapp/WEB-INF/jsp目录下,与jsp关联的js入口会被合并压缩后引入到jsp文件的body中。jsp关联的css会被抽离出一个单个的css文件引入的jsp文件head中。

    162 |

    以下几点需要注意一下

    163 |
      164 |
    • 如果您打包后的应用的Application Context不是/, 比如是/app,即访问地址都是基于http://localhost:8080/app,那么打包的时候webpack的publicPath参数记得配置/app,且jsp页面中所有的地址都需要带上${'$'}{pageContext.request.contextPath}/,在该项目框架中可以简写为${'$'}{ctx}/
    • 165 |
    • 如果您在打包后发现某些文件无法访问,请检查一下是否在tomcat环境下是否限制了某些文件类型的访问,比如检查一下web.xml中的相关配置。
    • 166 |
    167 |
    168 |
    169 |

    JSP页面

    170 |

    传统的JSP是在src/main/webapp下开发,在这个项目框架下开发jsp文件是在src/main/js/src/pages下开发。虽然开发目录不一致,但依然拥有传统jsp开发所有的特性。

    171 |
      172 |
    • 模板嵌套,比如使用${fn:escapeXml("")}或者<%@include file=""%>
    • 173 |
    • el表达式,${fn:escapeXml(", 等都可以使用
    • 174 |
    • 嵌入Java代码 比如使用<% out.println("hello world"); %>
    • 175 |
    • 支持热部署。配置好启动tomcat相关参数。在修改完jsp保存文件后,约10秒后刷新页面就可以看到页面的变化。如果等不及10秒或者页面一直不刷新,可以先点击idea菜单File->Syncronize>同步文件(快捷键Ctrl+Alt+Y),然后在点击Run的左侧第三个按钮后选择Update classes and resources手动更新,之后就刷新页面就可以看到最新出的页面。
    • 176 |
    177 |

    实际在npm run dev的时候,pages目录下的jsp会作为htmlWebpackPlugin插件的模板文件,每次修改pages下的文件都会被输出到webapp/WEB-INF/jsp下的相对目录。需要了解具体原理,请前往核心章节

    178 |
    179 |
    180 |

    自定义标签库

    181 |

    除了标准的c, fmt, fn标签库外,您也可以自定义标签库。

    182 |
      183 |
    • 首先在static/WEB-INF/tld新建一个tld,比如elftld
    • 184 |
    • 然后jsp页面引入,<%@ taglib prefix="elf" uri="/WEB-INF/tld/elfunc.tld" %>
    • 185 |
    186 |

    注意的是,在jsp页面的地址必须以/WEB-INF/开头,而实际开发jsp的路径是在js/src/pages目录下,导致idea无法正常解析pages目录下jsp中tld文件路径,在使用自定义标签的时候也无法自动补全。不过可以正常运行,实际开发过程影响不大。如果您有更好的解决方案,请与我们联系。

    187 |
    188 |
    189 |

    语法转换

    190 |

    因为了使用了webpack作为打包工具,您可以轻松对js和css进行语法转换,目前支持:

    191 |
      192 |
    • es6, stage-2
    • 193 |
    • postcss
    • 194 |
    • less, sass, scss 需要额外装对应的loader即可支持
    • 195 |
    196 |
    197 |
    198 |

    热更新

    199 |

    在开发单页应用的过程中,有一个很棒的特性就是热更新,修改了js文件,页面实时就会触发更新。

    200 |

    在此项目框架下,您依然可以享受到热更新带来的喜悦,在您修改js和css的时候,页面都会实时触发更新。

    201 |
    202 |
    203 |

    VUE

    204 |
    205 | 206 |
    207 |
    208 |
    209 |

    核心

    210 |

    该项目融合了webpack和jsp两者的特性实现了多页应用,这很酷。那到底是如何实现的呢。这里我们从搭建项目遇到的问题来讲讲最核心的几个问题是如何解决的。

    211 |

    HtmlWebpackPlugin

    212 |

    使用webpack实现多页应用,很容易联想到配置多个entry入口,每一个entry对应一个HtmlWebpackPlugin。jsp文件作为HtmlWebpackPlugin的模板文件,在entry的js在打包之后会插入到body下。该项目也是按照这样的搭建的。

    213 |

    这里有几点需要注意

    214 |
      215 |
    • HtmlWebpackPlugin解析jsp文件需要对应的loader,需要在webpack中配置{ test: /\.jsp$/, loader: 'raw-loader' },这里使用raw-loader进行纯文本拷贝。如果您有更适合jsp的loader,那么您可以赋予jsp文件特多的特性。
    • 216 |
    • 因为jsp可以被嵌套,这些被嵌套的jsp,并不是入口的jsp。所有只有是入口的jsp在配合HtmlWebpackPlugin插件的会额外添加{inject: 'body'}参数
    • 217 |
    • 那如何规定哪些jsp是入口文件呢?我们是通过配置来约定entry的js与jsp的关联关系,配置文件在config/js-jsp-map.js中。
    • 218 |
    219 |

    proxy反代

    220 |

    tomcat是跑在8080端口下的,webpack-dev-server是跑在8081端口下的,是两个不同应用。那岂不是开发jsp要在tomcat下编写调试,开发js在webpack-dev-server调试。这样的话岂不是很麻烦。

    221 |

    庆幸的webpack-dev-server有一个proxy参数,我们利用proxy把访问webpack-dev-server的请求都反代到8080下。这样实际开发过程中浏览器只要打开8081端口页面就可以。这样就做到兼顾jsp服务端渲染的功能,以及webpack语法转换,热更新的功能。tomcat只有在必要的时候重启一下就好。

    222 |

    这里有几点需要注意

    223 |
      224 |
    • npm run dev和启动tomcat并没有顺序要求,不过在浏览器访问8081前需要把这两个服务都启动起来。
    • 225 |
    • 当涉及到jsp文件有新增删除,或者static目录下的文件有新增编辑删除时,需要重新npm run dev和重启tomcat。记住一点,如果有文件新增和删除,最好都把这两个服务都重启一下肯定是没有问题的。
    • 226 |
    227 |

    WriteFilePlugin

    228 |

    我们知道webpack-dev-server是使用内存中的文件系统。而jsp页面最终是要发布到tomcat的,内存中的jsp文件并不能被idea监听,这样即使最终输出的jsp发生改变也无法被deploy到tomcat。

    229 |

    庆幸我们找到了一个webpack的插件WriteFilePlugin,它能强制把webpack-dev-server程序的输出的文件写到磁盘文件系统上。

    230 |

    这里有几点需要注意

    231 |
      232 |
    • 虽然通过WriteFilePlugin的jsp文件输出到磁盘上了,但是因为不是通过idea直接修改,idea还是无法立刻同步这些文件。idea同步并发布jsp文件会有10s的延迟。如果等不及10秒或者页面一直不刷新,可以先点击idea菜单File->Syncronize>同步文件(快捷键Ctrl+Alt+Y),然后在点击Run的左侧第三个按钮后选择Update classes and resources手动更新,之后就刷新页面就可以看到最新出的页面。
    • 233 |
    234 |

    结语

    235 |

    这个思路其实不仅适用tomcat下的jsp多页应用,同样也是适用node作为服务器的多页应用。Enjoy it!

    236 |
    237 |
    238 |
    239 | 240 | 241 | 242 | 243 | 244 | 245 | -------------------------------------------------------------------------------- /src/main/webapp/static/js/manifest.f93839dfcf180f0b2afc.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack:///static/js/manifest.f93839dfcf180f0b2afc.js","webpack:///webpack/bootstrap 44f422af28d717dc90ef"],"names":["modules","__webpack_require__","moduleId","installedModules","exports","module","i","l","call","parentJsonpFunction","window","chunkIds","moreModules","executeModules","chunkId","result","resolves","length","installedChunks","push","Object","prototype","hasOwnProperty","shift","s","4","e","onScriptComplete","script","onerror","onload","clearTimeout","timeout","chunk","Error","undefined","installedChunkData","Promise","resolve","promise","reject","head","document","getElementsByTagName","createElement","type","charset","async","nc","setAttribute","src","p","0","1","2","3","setTimeout","appendChild","m","c","d","name","getter","o","defineProperty","configurable","enumerable","get","n","__esModule","object","property","oe","err","console","error"],"mappings":"CAAS,SAAUA,GCuCnB,QAAAC,GAAAC,GAGA,GAAAC,EAAAD,GACA,MAAAC,GAAAD,GAAAE,OAGA,IAAAC,GAAAF,EAAAD,IACAI,EAAAJ,EACAK,GAAA,EACAH,WAUA,OANAJ,GAAAE,GAAAM,KAAAH,EAAAD,QAAAC,IAAAD,QAAAH,GAGAI,EAAAE,GAAA,EAGAF,EAAAD,QA1DA,GAAAK,GAAAC,OAAA,YACAA,QAAA,sBAAAC,EAAAC,EAAAC,GAIA,IADA,GAAAX,GAAAY,EAAAC,EAAAT,EAAA,EAAAU,KACQV,EAAAK,EAAAM,OAAoBX,IAC5BQ,EAAAH,EAAAL,GACAY,EAAAJ,IACAE,EAAAG,KAAAD,EAAAJ,GAAA,IAEAI,EAAAJ,GAAA,CAEA,KAAAZ,IAAAU,GACAQ,OAAAC,UAAAC,eAAAd,KAAAI,EAAAV,KACAF,EAAAE,GAAAU,EAAAV,GAIA,KADAO,KAAAE,EAAAC,EAAAC,GACAG,EAAAC,QACAD,EAAAO,SAEA,IAAAV,EACA,IAAAP,EAAA,EAAYA,EAAAO,EAAAI,OAA2BX,IACvCS,EAAAd,IAAAuB,EAAAX,EAAAP,GAGA,OAAAS,GAIA,IAAAZ,MAGAe,GACAO,EAAA,EA6BAxB,GAAAyB,EAAA,SAAAZ,GA+BA,QAAAa,KAEAC,EAAAC,QAAAD,EAAAE,OAAA,KACAC,aAAAC,EACA,IAAAC,GAAAf,EAAAJ,EACA,KAAAmB,IACAA,GACAA,EAAA,MAAAC,OAAA,iBAAApB,EAAA,aAEAI,EAAAJ,OAAAqB,IAvCA,GAAAC,GAAAlB,EAAAJ,EACA,QAAAsB,EACA,UAAAC,SAAA,SAAAC,GAA0CA,KAI1C,IAAAF,EACA,MAAAA,GAAA,EAIA,IAAAG,GAAA,GAAAF,SAAA,SAAAC,EAAAE,GACAJ,EAAAlB,EAAAJ,IAAAwB,EAAAE,IAEAJ,GAAA,GAAAG,CAGA,IAAAE,GAAAC,SAAAC,qBAAA,WACAf,EAAAc,SAAAE,cAAA,SACAhB,GAAAiB,KAAA,kBACAjB,EAAAkB,QAAA,QACAlB,EAAAmB,OAAA,EACAnB,EAAAI,QAAA,KAEA/B,EAAA+C,IACApB,EAAAqB,aAAA,QAAAhD,EAAA+C,IAEApB,EAAAsB,IAAAjD,EAAAkD,EAAA,aAAArC,EAAA,WAA8EsC,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,wBAA4GzC,GAAA,KAC1L,IAAAkB,GAAAwB,WAAA7B,EAAA,KAgBA,OAfAC,GAAAC,QAAAD,EAAAE,OAAAH,EAaAc,EAAAgB,YAAA7B,GAEAW,GAIAtC,EAAAyD,EAAA1D,EAGAC,EAAA0D,EAAAxD,EAGAF,EAAA2D,EAAA,SAAAxD,EAAAyD,EAAAC,GACA7D,EAAA8D,EAAA3D,EAAAyD,IACAzC,OAAA4C,eAAA5D,EAAAyD,GACAI,cAAA,EACAC,YAAA,EACAC,IAAAL,KAMA7D,EAAAmE,EAAA,SAAA/D,GACA,GAAAyD,GAAAzD,KAAAgE,WACA,WAA2B,MAAAhE,GAAA,SAC3B,WAAiC,MAAAA,GAEjC,OADAJ,GAAA2D,EAAAE,EAAA,IAAAA,GACAA,GAIA7D,EAAA8D,EAAA,SAAAO,EAAAC,GAAsD,MAAAnD,QAAAC,UAAAC,eAAAd,KAAA8D,EAAAC,IAGtDtE,EAAAkD,EAAA,IAGAlD,EAAAuE,GAAA,SAAAC,GAA8D,KAApBC,SAAAC,MAAAF,GAAoBA","file":"static/js/manifest.f93839dfcf180f0b2afc.js","sourcesContent":["/******/ (function(modules) { // webpackBootstrap\n/******/ \t// install a JSONP callback for chunk loading\n/******/ \tvar parentJsonpFunction = window[\"webpackJsonp\"];\n/******/ \twindow[\"webpackJsonp\"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) {\n/******/ \t\t// add \"moreModules\" to the modules object,\n/******/ \t\t// then flag all \"chunkIds\" as loaded and fire callback\n/******/ \t\tvar moduleId, chunkId, i = 0, resolves = [], result;\n/******/ \t\tfor(;i < chunkIds.length; i++) {\n/******/ \t\t\tchunkId = chunkIds[i];\n/******/ \t\t\tif(installedChunks[chunkId]) {\n/******/ \t\t\t\tresolves.push(installedChunks[chunkId][0]);\n/******/ \t\t\t}\n/******/ \t\t\tinstalledChunks[chunkId] = 0;\n/******/ \t\t}\n/******/ \t\tfor(moduleId in moreModules) {\n/******/ \t\t\tif(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {\n/******/ \t\t\t\tmodules[moduleId] = moreModules[moduleId];\n/******/ \t\t\t}\n/******/ \t\t}\n/******/ \t\tif(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules, executeModules);\n/******/ \t\twhile(resolves.length) {\n/******/ \t\t\tresolves.shift()();\n/******/ \t\t}\n/******/ \t\tif(executeModules) {\n/******/ \t\t\tfor(i=0; i < executeModules.length; i++) {\n/******/ \t\t\t\tresult = __webpack_require__(__webpack_require__.s = executeModules[i]);\n/******/ \t\t\t}\n/******/ \t\t}\n/******/ \t\treturn result;\n/******/ \t};\n/******/\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// objects to store loaded and loading chunks\n/******/ \tvar installedChunks = {\n/******/ \t\t4: 0\n/******/ \t};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId]) {\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/ \t// This file contains only the entry chunk.\n/******/ \t// The chunk loading function for additional chunks\n/******/ \t__webpack_require__.e = function requireEnsure(chunkId) {\n/******/ \t\tvar installedChunkData = installedChunks[chunkId];\n/******/ \t\tif(installedChunkData === 0) {\n/******/ \t\t\treturn new Promise(function(resolve) { resolve(); });\n/******/ \t\t}\n/******/\n/******/ \t\t// a Promise means \"currently loading\".\n/******/ \t\tif(installedChunkData) {\n/******/ \t\t\treturn installedChunkData[2];\n/******/ \t\t}\n/******/\n/******/ \t\t// setup Promise in chunk cache\n/******/ \t\tvar promise = new Promise(function(resolve, reject) {\n/******/ \t\t\tinstalledChunkData = installedChunks[chunkId] = [resolve, reject];\n/******/ \t\t});\n/******/ \t\tinstalledChunkData[2] = promise;\n/******/\n/******/ \t\t// start chunk loading\n/******/ \t\tvar head = document.getElementsByTagName('head')[0];\n/******/ \t\tvar script = document.createElement('script');\n/******/ \t\tscript.type = 'text/javascript';\n/******/ \t\tscript.charset = 'utf-8';\n/******/ \t\tscript.async = true;\n/******/ \t\tscript.timeout = 120000;\n/******/\n/******/ \t\tif (__webpack_require__.nc) {\n/******/ \t\t\tscript.setAttribute(\"nonce\", __webpack_require__.nc);\n/******/ \t\t}\n/******/ \t\tscript.src = __webpack_require__.p + \"static/js/\" + chunkId + \".chunk.\" + {\"0\":\"0adb37f44d19aeb70c20\",\"1\":\"d7ebb5145fef16460537\",\"2\":\"ae1113387e1befd7ff8b\",\"3\":\"f9d8e14098eb453538be\"}[chunkId] + \".js\";\n/******/ \t\tvar timeout = setTimeout(onScriptComplete, 120000);\n/******/ \t\tscript.onerror = script.onload = onScriptComplete;\n/******/ \t\tfunction onScriptComplete() {\n/******/ \t\t\t// avoid mem leaks in IE.\n/******/ \t\t\tscript.onerror = script.onload = null;\n/******/ \t\t\tclearTimeout(timeout);\n/******/ \t\t\tvar chunk = installedChunks[chunkId];\n/******/ \t\t\tif(chunk !== 0) {\n/******/ \t\t\t\tif(chunk) {\n/******/ \t\t\t\t\tchunk[1](new Error('Loading chunk ' + chunkId + ' failed.'));\n/******/ \t\t\t\t}\n/******/ \t\t\t\tinstalledChunks[chunkId] = undefined;\n/******/ \t\t\t}\n/******/ \t\t};\n/******/ \t\thead.appendChild(script);\n/******/\n/******/ \t\treturn promise;\n/******/ \t};\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__webpack_require__.d = function(exports, name, getter) {\n/******/ \t\tif(!__webpack_require__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, {\n/******/ \t\t\t\tconfigurable: false,\n/******/ \t\t\t\tenumerable: true,\n/******/ \t\t\t\tget: getter\n/******/ \t\t\t});\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__webpack_require__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__webpack_require__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"/\";\n/******/\n/******/ \t// on error function for async loading\n/******/ \t__webpack_require__.oe = function(err) { console.error(err); throw err; };\n/******/ })\n/************************************************************************/\n/******/ ([]);\n\n\n// WEBPACK FOOTER //\n// static/js/manifest.f93839dfcf180f0b2afc.js"," \t// install a JSONP callback for chunk loading\n \tvar parentJsonpFunction = window[\"webpackJsonp\"];\n \twindow[\"webpackJsonp\"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) {\n \t\t// add \"moreModules\" to the modules object,\n \t\t// then flag all \"chunkIds\" as loaded and fire callback\n \t\tvar moduleId, chunkId, i = 0, resolves = [], result;\n \t\tfor(;i < chunkIds.length; i++) {\n \t\t\tchunkId = chunkIds[i];\n \t\t\tif(installedChunks[chunkId]) {\n \t\t\t\tresolves.push(installedChunks[chunkId][0]);\n \t\t\t}\n \t\t\tinstalledChunks[chunkId] = 0;\n \t\t}\n \t\tfor(moduleId in moreModules) {\n \t\t\tif(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {\n \t\t\t\tmodules[moduleId] = moreModules[moduleId];\n \t\t\t}\n \t\t}\n \t\tif(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules, executeModules);\n \t\twhile(resolves.length) {\n \t\t\tresolves.shift()();\n \t\t}\n \t\tif(executeModules) {\n \t\t\tfor(i=0; i < executeModules.length; i++) {\n \t\t\t\tresult = __webpack_require__(__webpack_require__.s = executeModules[i]);\n \t\t\t}\n \t\t}\n \t\treturn result;\n \t};\n\n \t// The module cache\n \tvar installedModules = {};\n\n \t// objects to store loaded and loading chunks\n \tvar installedChunks = {\n \t\t4: 0\n \t};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n \t// This file contains only the entry chunk.\n \t// The chunk loading function for additional chunks\n \t__webpack_require__.e = function requireEnsure(chunkId) {\n \t\tvar installedChunkData = installedChunks[chunkId];\n \t\tif(installedChunkData === 0) {\n \t\t\treturn new Promise(function(resolve) { resolve(); });\n \t\t}\n\n \t\t// a Promise means \"currently loading\".\n \t\tif(installedChunkData) {\n \t\t\treturn installedChunkData[2];\n \t\t}\n\n \t\t// setup Promise in chunk cache\n \t\tvar promise = new Promise(function(resolve, reject) {\n \t\t\tinstalledChunkData = installedChunks[chunkId] = [resolve, reject];\n \t\t});\n \t\tinstalledChunkData[2] = promise;\n\n \t\t// start chunk loading\n \t\tvar head = document.getElementsByTagName('head')[0];\n \t\tvar script = document.createElement('script');\n \t\tscript.type = 'text/javascript';\n \t\tscript.charset = 'utf-8';\n \t\tscript.async = true;\n \t\tscript.timeout = 120000;\n\n \t\tif (__webpack_require__.nc) {\n \t\t\tscript.setAttribute(\"nonce\", __webpack_require__.nc);\n \t\t}\n \t\tscript.src = __webpack_require__.p + \"static/js/\" + chunkId + \".chunk.\" + {\"0\":\"0adb37f44d19aeb70c20\",\"1\":\"d7ebb5145fef16460537\",\"2\":\"ae1113387e1befd7ff8b\",\"3\":\"f9d8e14098eb453538be\"}[chunkId] + \".js\";\n \t\tvar timeout = setTimeout(onScriptComplete, 120000);\n \t\tscript.onerror = script.onload = onScriptComplete;\n \t\tfunction onScriptComplete() {\n \t\t\t// avoid mem leaks in IE.\n \t\t\tscript.onerror = script.onload = null;\n \t\t\tclearTimeout(timeout);\n \t\t\tvar chunk = installedChunks[chunkId];\n \t\t\tif(chunk !== 0) {\n \t\t\t\tif(chunk) {\n \t\t\t\t\tchunk[1](new Error('Loading chunk ' + chunkId + ' failed.'));\n \t\t\t\t}\n \t\t\t\tinstalledChunks[chunkId] = undefined;\n \t\t\t}\n \t\t};\n \t\thead.appendChild(script);\n\n \t\treturn promise;\n \t};\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"/\";\n\n \t// on error function for async loading\n \t__webpack_require__.oe = function(err) { console.error(err); throw err; };\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 44f422af28d717dc90ef"],"sourceRoot":""} -------------------------------------------------------------------------------- /src/main/webapp/static/js/start.d7ebb5145fef16460537.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack:///static/js/start.d7ebb5145fef16460537.js","webpack:///external \"window.$\"","webpack:///src/pages/start/my-component.vue","webpack:///./src/pages/start/my-component.vue?e0f2","webpack:///./src/pages/start/my-component.vue","webpack:///./src/pages/start/index.js","webpack:///./src/polyfills/console.js","webpack:///./src/polyfills/promise.js"],"names":["webpackJsonp","0iPh","module","exports","window","$","1","__webpack_require__","IHve","__webpack_exports__","Object","defineProperty","value","external__window_$_","external__window_$__default","n","vue","vue_default","my_component","data","message","render","_vm","this","_h","$createElement","_c","_self","_v","_s","_m","staticRenderFns","esExports","start_my_component","normalizeComponent","Component","pages_start_my_component","click","console","log","location","pathname","replace","hostname","hash","target","length","slice","animate","scrollTop","offset","top","collapse","scrollspy","a","el","components","myComponent","Pp/C","method","noop","methods","a2c4","cZNe","dist","dist_default","Promise","h2zT","i5Z1","__WEBPACK_IMPORTED_MODULE_0__styles_index_css__"],"mappings":"AAAAA,cAAc,IAERC,OACA,SAAUC,EAAQC,GCHxBD,EAAAC,QAAAC,OAAAC,GDSMC,EACA,SAAUJ,EAAQC,EAASI,GAEjCA,EAAoB,QACpBL,EAAOC,QAAUI,EAAoB,SAK/BC,KACA,SAAUN,EAAQO,EAAqBF,GAE7C,YACAG,QAAOC,eAAeF,EAAqB,cAAgBG,OAAO,GAGlE,IAOIC,IAPON,EAAoB,QAGfA,EAAoB,QAIVA,EAAoB,SAC1CO,EAA2CP,EAAoBQ,EAAEF,GAGjEG,EAAMT,EAAoB,QAC1BU,EAA2BV,EAAoBQ,EAAEC,GE5BrDE,GF0CEC,KAAM,WACJ,OACEC,QEvCN,qDCdAC,EAAA,WAA0B,GAAAC,GAAAC,KAAaC,EAAAF,EAAAG,eAA0BC,EAAAJ,EAAAK,MAAAD,IAAAF,CAAwB,OAAAE,GAAA,OAAAA,EAAA,KAAAJ,EAAAM,GAAAN,EAAAO,GAAAP,EAAAF,YAAAE,EAAAM,GAAA,KAAAN,EAAAQ,GAAA,MACzFC,GAAA,WAAoC,GAAAT,GAAAC,KAAaC,EAAAF,EAAAG,eAA0BC,EAAAJ,EAAAK,MAAAD,IAAAF,CAAwB,OAAAE,GAAA,MAAAA,EAAA,MAAAJ,EAAAM,GAAA,yCAAAN,EAAAM,GAAA,KAAAF,EAAA,MAAAJ,EAAAM,GAAA,kCACnGI,GAAiBX,SAAAU,mBACjBE,EAAA,ECHAC,EAAA3B,EAAA,QAcA4B,EAAAD,EACAhB,EACAe,GATA,EAEA,KAEA,KAEA,MAUAG,EAAAD,EAAA,OChBArB,KAAE,kDAAkDuB,MAAM,WAExD,GADAC,QAAQC,IAAIC,SAASC,SAAUlB,KAAKkB,UAChCD,SAASC,SAASC,QAAQ,MAAO,MAAQnB,KAAKkB,SAASC,QAAQ,MAAO,KAAOF,SAASG,WAAapB,KAAKoB,SAAU,CACpHL,QAAQC,IAAIhB,KAAKqB,KACjB,IAAIC,GAAS/B,IAAES,KAAKqB,KAEpB,IADAC,EAASA,EAAOC,OAASD,EAAS/B,IAAE,SAAWS,KAAKqB,KAAKG,MAAM,GAAK,KAChEF,EAAOC,OAIT,MAHAhC,KAAE,cAAckC,SACdC,UAAYJ,EAAOK,SAASC,IAAM,IACjC,MACI,KAMbrC,IAAE,sBAAsBuB,MAAM,WAC5BvB,IAAE,oBAAoBsC,SAAS,UAIjCtC,IAAE,QAAQuC,WACRR,OAAQ,WACRK,OAAQ,KAGV,GAAIjC,GAAAqC,GACFC,GAAI,WACJC,YACEC,YAAArB,ML+FEsB,OACA,SAAUxD,EAAQC,IMpIvB,WAYC,IAXA,GAAIwD,GACAC,EAAO,aACPC,GACF,SAAU,QAAS,QAAS,QAAS,MAAO,SAAU,QACtD,YAAa,QAAS,iBAAkB,WAAY,OAAQ,MAC5D,eAAgB,UAAW,aAAc,QAAS,OAAQ,UAC1D,YAAa,QAAS,QAEpBf,EAASe,EAAQf,OACjBR,EAAWlC,OAAOkC,QAAUlC,OAAOkC,YAEhCQ,KACLa,EAASE,EAAQf,GAGZR,EAAQqB,KACXrB,EAAQqB,GAAUC,ONwIlBE,KACA,SAAU5D,EAAQC,KAMlB4D,KACA,SAAU7D,EAAQO,EAAqBF,GAE7C,YACAG,QAAOC,eAAeF,EAAqB,cAAgBG,OAAO,GAGlE,IAAIoD,GAAOzD,EAAoB,QAC3B0D,EAA4B1D,EAAoBQ,EAAEiD,EOtKtD5D,QAAO8D,QAAUD,EAAAX,CP6KH/C,GAAoB,QAItBA,EAAoB,QAIvBA,EAAoB,QAIlBA,EAAoB,QAIdA,EAAoB,QAIjBA,EAAoB,QAIzBA,EAAoB,QAIpBA,EAAoB,QAItBA,EAAoB,QAIvBA,EAAoB,QAIjBA,EAAoB,QAInBA,EAAoB,QAItBA,EAAoB,SAqB1B4D,KACA,SAAUjE,EAAQC,KAMlBiE,KACA,SAAUlE,EAAQO,EAAqBF,GAE7C,YACqB,IAAI8D,GAAkD9D,EAAoB,OACZA,GAAoBQ,EAAEsD,MAKtG","file":"static/js/start.d7ebb5145fef16460537.js","sourcesContent":["webpackJsonp([1],{\n\n/***/ \"0iPh\":\n/***/ (function(module, exports) {\n\nmodule.exports = window.$;\n\n/***/ }),\n\n/***/ 1:\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(\"cZNe\");\nmodule.exports = __webpack_require__(\"IHve\");\n\n\n/***/ }),\n\n/***/ \"IHve\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\nObject.defineProperty(__webpack_exports__, \"__esModule\", { value: true });\n\n// EXTERNAL MODULE: ./src/shares/page/index.js\nvar page = __webpack_require__(\"i5Z1\");\n\n// EXTERNAL MODULE: ./src/pages/start/dashboard.css\nvar dashboard = __webpack_require__(\"a2c4\");\nvar dashboard_default = /*#__PURE__*/__webpack_require__.n(dashboard);\n\n// EXTERNAL MODULE: external \"window.$\"\nvar external__window_$_ = __webpack_require__(\"0iPh\");\nvar external__window_$__default = /*#__PURE__*/__webpack_require__.n(external__window_$_);\n\n// EXTERNAL MODULE: ./node_modules/vue/dist/vue.js\nvar vue = __webpack_require__(\"4bK6\");\nvar vue_default = /*#__PURE__*/__webpack_require__.n(vue);\n\n// CONCATENATED MODULE: ./node_modules/babel-loader/lib!./node_modules/vue-loader/lib/selector.js?type=script&index=0!./src/pages/start/my-component.vue\n//\n//\n//\n//\n//\n//\n//\n//\n//\n\n/* harmony default export */ var my_component = ({\n data: function data() {\n return {\n message: '该项目已经默认支持Vue。这一章节也是用VUE编写的,你可以尽情的享受VUE带来的编码的快乐。'\n };\n }\n});\n// CONCATENATED MODULE: ./node_modules/vue-loader/lib/template-compiler?{\"id\":\"data-v-6795775c\",\"hasScoped\":false,\"transformToRequire\":{\"video\":\"src\",\"source\":\"src\",\"img\":\"src\",\"image\":\"xlink:href\"},\"buble\":{\"transforms\":{}}}!./node_modules/vue-loader/lib/selector.js?type=template&index=0!./src/pages/start/my-component.vue\nvar render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',[_c('p',[_vm._v(_vm._s(_vm.message))]),_vm._v(\" \"),_vm._m(0)])}\nvar staticRenderFns = [function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('ul',[_c('li',[_vm._v(\"您可以给idea添加vue.js插件,这样也可以直接使用.vue文件。\")]),_vm._v(\" \"),_c('li',[_vm._v(\"js和css的语法转换在.vue文件中同样适用。\")])])}]\nvar esExports = { render: render, staticRenderFns: staticRenderFns }\n/* harmony default export */ var start_my_component = (esExports);\n// CONCATENATED MODULE: ./src/pages/start/my-component.vue\nvar normalizeComponent = __webpack_require__(\"VU/8\")\n/* script */\n\n\n/* template */\n\n/* template functional */\nvar __vue_template_functional__ = false\n/* styles */\nvar __vue_styles__ = null\n/* scopeId */\nvar __vue_scopeId__ = null\n/* moduleIdentifier (server only) */\nvar __vue_module_identifier__ = null\nvar Component = normalizeComponent(\n my_component,\n start_my_component,\n __vue_template_functional__,\n __vue_styles__,\n __vue_scopeId__,\n __vue_module_identifier__\n)\n\n/* harmony default export */ var pages_start_my_component = (Component.exports);\n\n// CONCATENATED MODULE: ./src/pages/start/index.js\n\n\n\n\n\n\n// Smooth scrolling using jQuery easing\nexternal__window_$__default()('a.js-scroll-trigger[href*=\"#\"]:not([href=\"#\"])').click(function () {\n console.log(location.pathname, this.pathname);\n if (location.pathname.replace(/^\\//, '') === this.pathname.replace(/^\\//, '') && location.hostname === this.hostname) {\n console.log(this.hash);\n var target = external__window_$__default()(this.hash);\n target = target.length ? target : external__window_$__default()('[name=' + this.hash.slice(1) + ']');\n if (target.length) {\n external__window_$__default()('html, body').animate({\n scrollTop: target.offset().top - 60\n }, 300);\n return false;\n }\n }\n});\n\n// Closes responsive menu when a scroll trigger link is clicked\nexternal__window_$__default()('.js-scroll-trigger').click(function () {\n external__window_$__default()('.navbar-collapse').collapse('hide');\n});\n\n// Activate scrollspy to add active class to navbar items on scroll\nexternal__window_$__default()('body').scrollspy({\n target: '#sideNav',\n offset: 80\n});\n\nnew vue_default.a({\n el: '#vue-app',\n components: {\n myComponent: pages_start_my_component\n }\n});\n\n/***/ }),\n\n/***/ \"Pp/C\":\n/***/ (function(module, exports) {\n\n(function () {\n var method;\n var noop = function noop() {};\n var methods = ['assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error', 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', 'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd', 'timeStamp', 'trace', 'warn'];\n var length = methods.length;\n var console = window.console = window.console || {};\n\n while (length--) {\n method = methods[length];\n\n // Only stub undefined methods.\n if (!console[method]) {\n console[method] = noop;\n }\n }\n})();\n\n/***/ }),\n\n/***/ \"a2c4\":\n/***/ (function(module, exports) {\n\n// removed by extract-text-webpack-plugin\n\n/***/ }),\n\n/***/ \"cZNe\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\nObject.defineProperty(__webpack_exports__, \"__esModule\", { value: true });\n\n// EXTERNAL MODULE: ./node_modules/nuo/dist/index.js\nvar dist = __webpack_require__(\"SbJX\");\nvar dist_default = /*#__PURE__*/__webpack_require__.n(dist);\n\n// CONCATENATED MODULE: ./src/polyfills/promise.js\n\n\nwindow.Promise = dist_default.a;\n// EXTERNAL MODULE: ./src/polyfills/console.js\nvar console = __webpack_require__(\"Pp/C\");\nvar console_default = /*#__PURE__*/__webpack_require__.n(console);\n\n// EXTERNAL MODULE: ./node_modules/core-js/es6/array.js\nvar array = __webpack_require__(\"cUYv\");\nvar array_default = /*#__PURE__*/__webpack_require__.n(array);\n\n// EXTERNAL MODULE: ./node_modules/core-js/fn/array/of.js\nvar of = __webpack_require__(\"PPkL\");\nvar of_default = /*#__PURE__*/__webpack_require__.n(of);\n\n// EXTERNAL MODULE: ./node_modules/core-js/fn/array/find.js\nvar find = __webpack_require__(\"0K64\");\nvar find_default = /*#__PURE__*/__webpack_require__.n(find);\n\n// EXTERNAL MODULE: ./node_modules/core-js/fn/array/find-index.js\nvar find_index = __webpack_require__(\"X8hh\");\nvar find_index_default = /*#__PURE__*/__webpack_require__.n(find_index);\n\n// EXTERNAL MODULE: ./node_modules/core-js/fn/object/assign.js\nvar object_assign = __webpack_require__(\"kLF+\");\nvar assign_default = /*#__PURE__*/__webpack_require__.n(object_assign);\n\n// EXTERNAL MODULE: ./node_modules/core-js/fn/array/includes.js\nvar includes = __webpack_require__(\"fB7P\");\nvar includes_default = /*#__PURE__*/__webpack_require__.n(includes);\n\n// EXTERNAL MODULE: ./node_modules/core-js/fn/array/iterator.js\nvar iterator = __webpack_require__(\"mBqO\");\nvar iterator_default = /*#__PURE__*/__webpack_require__.n(iterator);\n\n// EXTERNAL MODULE: ./node_modules/core-js/es6/string.js\nvar string = __webpack_require__(\"oFcf\");\nvar string_default = /*#__PURE__*/__webpack_require__.n(string);\n\n// EXTERNAL MODULE: ./node_modules/core-js/es6/map.js\nvar map = __webpack_require__(\"7N90\");\nvar map_default = /*#__PURE__*/__webpack_require__.n(map);\n\n// EXTERNAL MODULE: ./node_modules/core-js/es6/symbol.js\nvar symbol = __webpack_require__(\"wu3h\");\nvar symbol_default = /*#__PURE__*/__webpack_require__.n(symbol);\n\n// EXTERNAL MODULE: ./node_modules/regenerator-runtime/runtime.js\nvar runtime = __webpack_require__(\"SldL\");\nvar runtime_default = /*#__PURE__*/__webpack_require__.n(runtime);\n\n// EXTERNAL MODULE: ./node_modules/whatwg-fetch/fetch.js\nvar fetch = __webpack_require__(\"rplX\");\nvar fetch_default = /*#__PURE__*/__webpack_require__.n(fetch);\n\n// CONCATENATED MODULE: ./src/polyfills/index.js\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/***/ }),\n\n/***/ \"h2zT\":\n/***/ (function(module, exports) {\n\n// removed by extract-text-webpack-plugin\n\n/***/ }),\n\n/***/ \"i5Z1\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__styles_index_css__ = __webpack_require__(\"h2zT\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__styles_index_css___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0__styles_index_css__);\n\n\n/***/ })\n\n},[1]);\n\n\n// WEBPACK FOOTER //\n// static/js/start.d7ebb5145fef16460537.js","module.exports = window.$;\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"window.$\"\n// module id = 0iPh\n// module chunks = 1","\n\n\n\n\n// WEBPACK FOOTER //\n// src/pages/start/my-component.vue","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',[_c('p',[_vm._v(_vm._s(_vm.message))]),_vm._v(\" \"),_vm._m(0)])}\nvar staticRenderFns = [function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('ul',[_c('li',[_vm._v(\"您可以给idea添加vue.js插件,这样也可以直接使用.vue文件。\")]),_vm._v(\" \"),_c('li',[_vm._v(\"js和css的语法转换在.vue文件中同样适用。\")])])}]\nvar esExports = { render: render, staticRenderFns: staticRenderFns }\nexport default esExports\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./node_modules/vue-loader/lib/template-compiler?{\"id\":\"data-v-6795775c\",\"hasScoped\":false,\"transformToRequire\":{\"video\":\"src\",\"source\":\"src\",\"img\":\"src\",\"image\":\"xlink:href\"},\"buble\":{\"transforms\":{}}}!./node_modules/vue-loader/lib/selector.js?type=template&index=0!./src/pages/start/my-component.vue\n// module id = null\n// module chunks = ","var normalizeComponent = require(\"!../../../node_modules/vue-loader/lib/component-normalizer\")\n/* script */\nexport * from \"!!babel-loader!../../../node_modules/vue-loader/lib/selector?type=script&index=0!./my-component.vue\"\nimport __vue_script__ from \"!!babel-loader!../../../node_modules/vue-loader/lib/selector?type=script&index=0!./my-component.vue\"\n/* template */\nimport __vue_template__ from \"!!../../../node_modules/vue-loader/lib/template-compiler/index?{\\\"id\\\":\\\"data-v-6795775c\\\",\\\"hasScoped\\\":false,\\\"transformToRequire\\\":{\\\"video\\\":\\\"src\\\",\\\"source\\\":\\\"src\\\",\\\"img\\\":\\\"src\\\",\\\"image\\\":\\\"xlink:href\\\"},\\\"buble\\\":{\\\"transforms\\\":{}}}!../../../node_modules/vue-loader/lib/selector?type=template&index=0!./my-component.vue\"\n/* template functional */\nvar __vue_template_functional__ = false\n/* styles */\nvar __vue_styles__ = null\n/* scopeId */\nvar __vue_scopeId__ = null\n/* moduleIdentifier (server only) */\nvar __vue_module_identifier__ = null\nvar Component = normalizeComponent(\n __vue_script__,\n __vue_template__,\n __vue_template_functional__,\n __vue_styles__,\n __vue_scopeId__,\n __vue_module_identifier__\n)\n\nexport default Component.exports\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/pages/start/my-component.vue\n// module id = null\n// module chunks = ","import '@/shares/page'\nimport './dashboard.css'\nimport $ from 'jquery'\nimport Vue from 'vue'\nimport myComponent from './my-component'\n\n// Smooth scrolling using jQuery easing\n$('a.js-scroll-trigger[href*=\"#\"]:not([href=\"#\"])').click(function () {\n console.log(location.pathname, this.pathname)\n if (location.pathname.replace(/^\\//, '') === this.pathname.replace(/^\\//, '') && location.hostname === this.hostname) {\n console.log(this.hash)\n var target = $(this.hash)\n target = target.length ? target : $('[name=' + this.hash.slice(1) + ']')\n if (target.length) {\n $('html, body').animate({\n scrollTop: (target.offset().top - 60)\n }, 300)\n return false\n }\n }\n})\n\n// Closes responsive menu when a scroll trigger link is clicked\n$('.js-scroll-trigger').click(function () {\n $('.navbar-collapse').collapse('hide')\n})\n\n// Activate scrollspy to add active class to navbar items on scroll\n$('body').scrollspy({\n target: '#sideNav',\n offset: 80\n})\n\nnew Vue({\n el: '#vue-app',\n components: {\n myComponent\n }\n})\n\n\n\n// WEBPACK FOOTER //\n// ./src/pages/start/index.js","(function () {\n var method\n var noop = function () {}\n var methods = [\n 'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',\n 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',\n 'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',\n 'timeStamp', 'trace', 'warn'\n ]\n var length = methods.length\n var console = (window.console = window.console || {})\n\n while (length--) {\n method = methods[length]\n\n // Only stub undefined methods.\n if (!console[method]) {\n console[method] = noop\n }\n }\n}())\n\n\n\n// WEBPACK FOOTER //\n// ./src/polyfills/console.js","import Promise from 'nuo'\n\nwindow.Promise = Promise\n\n\n\n// WEBPACK FOOTER //\n// ./src/polyfills/promise.js"],"sourceRoot":""} --------------------------------------------------------------------------------