diff --git a/.gitignore b/.gitignore index d416ccc..58fa906 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ ### gradle ### .gradle -/build/ !gradle/wrapper/gradle-wrapper.jar ### STS ### @@ -23,7 +22,6 @@ rebel.xml ### NetBeans ### nbproject/private/ -build/ nbbuild/ dist/ nbdist/ diff --git a/doc/README.md b/doc/README.md new file mode 100644 index 0000000..01095b4 --- /dev/null +++ b/doc/README.md @@ -0,0 +1,64 @@ +# 编写的原因 + +写在前面,很多加入我们群里的人,都会问我们源码在哪里,现在仔细回答一下 + +1. 我们已经声明了,这是一个前后端分离的商城,而且分离的很彻底,java的后台管理系统不是jsp,使用vue写的,所以商城的后台管理在vue这个项目 https://gitee.com/gz-yami/mall4v ,启动完java,不要访问java的端口,启动vue,访问vue的端口页面,就能看到后台管理,就能上商品了!!! + +2. 和上面一样的,很多人问,前端的浏览商品的页面在哪里,小程序的代码在哪,其实就在这里 https://gitee.com/gz-yami/mall4m, 还有人用vscode,idea之类的打开小程序,说我们代码跑不起来,实际上,应该用微信开发工具去打开小程序的项目,去跑小程序的代码...我太难了 :cry: + +3. 有人会问你是不是将上面两个链接藏起来了,上面两个项目的链接都在readme里面写着,可是很多人都不读。 + +4. 还有人说什么不知道怎么配置微信支付,支付不能回调,登陆不了,请仔细看看开发环境的安装,看看你是不是少配置了什么配置文件 + +5. swagger文档怎么访问不了,其实路径是/doc.html + +6. 我们开源的刚上线直接申请通过了推荐项目,第一天就有100个星星,一个月就有1k的星星,大家都不是傻的,这代码是能用的,拜托...后来没怎么维护(整个流程都是好的,整个功能都是好的,都不知道维护啥),现在又开始维护了,星星也没了(如果你悄悄拿去做外包项目,觉得这个项目对你有用,就给个星星呗) + + +## 1.java开发环境安装 + + +### 1.开发环境 + +以下版本是最低要求的!!! 提问问题前请注意开发环境!! + +| 工具 | 版本 | +| ----- | ---- | +| jdk | 1.8+ | +| mysql | 5.7+ | +| redis | 3.2+ | + +### 2.启动 + +- 推荐使用idea,安装lombok插件后,使用idea导入maven项目 +- 将yami_shop.sql导入到mysql中,修改`application-dev.yml`更改 datasource.url、user、password +- 将mysql配置为不区分表名大小写 +- 通过修改`ma.properties` 修改微信小程序信息 +- 通过修改`mp.properties` 修改微信公众号信息 +- 通过修改`pay.properties` 修改微信支付信息 +- 通过修改`shop.properties` 修改七牛云、阿里大于等信息 +- 修改`api.properties` 修改当前接口所在域名,用于支付回调 +- 启动redis,端口6379 +- 通过`WebApplication`启动项目后台接口,`ApiApplication` 启动项目前端接口 + +## 2.vue开发环境安装 + +这是一套正常的vue启动流程。如果你无法理解,可能要先学习一下vue... + +推荐使用vs code + +1. 安装nodejs的开发环境 +2. 安装npm的淘宝镜像(一定要用淘宝镜像,不然有的依赖下载不完!!启动不了) +3. 使用淘宝镜像安装依赖 +4. 启动 + +## 3.小程序开发环境安装 + +使用“微信开发者工具” 导入项目,设置你小程序申请的appid打开项目。然后就可以用了 + +## 4.文档 + +这代码有没有文档呀? +当然有啦,你已经下载了,在doc这个文件夹上,实在不知道,我就给链接出来咯: + +### [https://gitee.com/gz-yami/mall4j/tree/master/doc](https://gitee.com/gz-yami/mall4j/tree/master/doc) diff --git a/mall4v/build/build.js b/mall4v/build/build.js new file mode 100644 index 0000000..955e9de --- /dev/null +++ b/mall4v/build/build.js @@ -0,0 +1,41 @@ +'use strict' +require('./check-versions')() + +process.env.NODE_ENV = 'production' + +const ora = require('ora') +const rm = require('rimraf') +const path = require('path') +const chalk = require('chalk') +const webpack = require('webpack') +const config = require('../config') +const webpackConfig = require('./webpack.prod.conf') + +const spinner = ora('building for production...') +spinner.start() + +rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { + if (err) throw err + webpack(webpackConfig, (err, stats) => { + spinner.stop() + if (err) throw err + process.stdout.write(stats.toString({ + colors: true, + modules: false, + children: false, + chunks: false, + chunkModules: false + }) + '\n\n') + + if (stats.hasErrors()) { + console.log(chalk.red(' Build failed with errors.\n')) + process.exit(1) + } + + console.log(chalk.cyan(' Build complete.\n')) + console.log(chalk.yellow( + ' Tip: built files are meant to be served over an HTTP server.\n' + + ' Opening index.html over file:// won\'t work.\n' + )) + }) +}) diff --git a/mall4v/build/check-versions.js b/mall4v/build/check-versions.js new file mode 100644 index 0000000..3ef972a --- /dev/null +++ b/mall4v/build/check-versions.js @@ -0,0 +1,54 @@ +'use strict' +const chalk = require('chalk') +const semver = require('semver') +const packageConfig = require('../package.json') +const shell = require('shelljs') + +function exec (cmd) { + return require('child_process').execSync(cmd).toString().trim() +} + +const versionRequirements = [ + { + name: 'node', + currentVersion: semver.clean(process.version), + versionRequirement: packageConfig.engines.node + } +] + +if (shell.which('npm')) { + versionRequirements.push({ + name: 'npm', + currentVersion: exec('npm --version'), + versionRequirement: packageConfig.engines.npm + }) +} + +module.exports = function () { + const warnings = [] + + for (let i = 0; i < versionRequirements.length; i++) { + const mod = versionRequirements[i] + + if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { + warnings.push(mod.name + ': ' + + chalk.red(mod.currentVersion) + ' should be ' + + chalk.green(mod.versionRequirement) + ) + } + } + + if (warnings.length) { + console.log('') + console.log(chalk.yellow('To use this template, you must update following to modules:')) + console.log() + + for (let i = 0; i < warnings.length; i++) { + const warning = warnings[i] + console.log(' ' + warning) + } + + console.log() + process.exit(1) + } +} diff --git a/mall4v/build/utils.js b/mall4v/build/utils.js new file mode 100644 index 0000000..4b117ed --- /dev/null +++ b/mall4v/build/utils.js @@ -0,0 +1,102 @@ +'use strict' +const path = require('path') +const config = require('../config') +const ExtractTextPlugin = require('extract-text-webpack-plugin') +const packageConfig = require('../package.json') + +exports.assetsPath = function (_path) { + const assetsSubDirectory = process.env.NODE_ENV === 'production' + ? config.build.assetsSubDirectory + : config.dev.assetsSubDirectory + + return path.posix.join(assetsSubDirectory, _path) +} + +exports.cssLoaders = function (options) { + options = options || {} + + const cssLoader = { + loader: 'css-loader', + options: { + sourceMap: options.sourceMap + } + } + + const postcssLoader = { + loader: 'postcss-loader', + options: { + sourceMap: options.sourceMap + } + } + + // generate loader string to be used with extract text plugin + function generateLoaders (loader, loaderOptions) { + const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader] + + if (loader) { + loaders.push({ + loader: loader + '-loader', + options: Object.assign({}, loaderOptions, { + sourceMap: options.sourceMap + }) + }) + } + + // Extract CSS when that option is specified + // (which is the case during production build) + if (options.extract) { + return ExtractTextPlugin.extract({ + use: loaders, + publicPath: '../../', + fallback: 'vue-style-loader' + }) + } else { + return ['vue-style-loader'].concat(loaders) + } + } + + // https://vue-loader.vuejs.org/en/configurations/extract-css.html + return { + css: generateLoaders(), + postcss: generateLoaders(), + less: generateLoaders('less'), + sass: generateLoaders('sass', { indentedSyntax: true }), + scss: generateLoaders('sass'), + stylus: generateLoaders('stylus'), + styl: generateLoaders('stylus') + } +} + +// Generate loaders for standalone style files (outside of .vue) +exports.styleLoaders = function (options) { + const output = [] + const loaders = exports.cssLoaders(options) + + for (const extension in loaders) { + const loader = loaders[extension] + output.push({ + test: new RegExp('\\.' + extension + '$'), + use: loader + }) + } + + return output +} + +exports.createNotifierCallback = () => { + const notifier = require('node-notifier') + + return (severity, errors) => { + if (severity !== 'error') return + + const error = errors[0] + const filename = error.file && error.file.split('!').pop() + + notifier.notify({ + title: packageConfig.name, + message: severity + ': ' + error.name, + subtitle: filename || '', + icon: path.join(__dirname, 'logo.png') + }) + } +} diff --git a/mall4v/build/vue-loader.conf.js b/mall4v/build/vue-loader.conf.js new file mode 100644 index 0000000..33ed58b --- /dev/null +++ b/mall4v/build/vue-loader.conf.js @@ -0,0 +1,22 @@ +'use strict' +const utils = require('./utils') +const config = require('../config') +const isProduction = process.env.NODE_ENV === 'production' +const sourceMapEnabled = isProduction + ? config.build.productionSourceMap + : config.dev.cssSourceMap + +module.exports = { + loaders: utils.cssLoaders({ + sourceMap: sourceMapEnabled, + extract: isProduction + }), + cssSourceMap: sourceMapEnabled, + cacheBusting: config.dev.cacheBusting, + transformToRequire: { + video: ['src', 'poster'], + source: 'src', + img: 'src', + image: 'xlink:href' + } +} diff --git a/mall4v/build/webpack.base.conf.js b/mall4v/build/webpack.base.conf.js new file mode 100644 index 0000000..4abc1ab --- /dev/null +++ b/mall4v/build/webpack.base.conf.js @@ -0,0 +1,103 @@ +'use strict' +const path = require('path') +const utils = require('./utils') +const config = require('../config') +const vueLoaderConfig = require('./vue-loader.conf') + +function resolve (dir) { + return path.join(__dirname, '..', dir) +} + +const createLintingRule = () => ({ + test: /\.(js|vue)$/, + loader: 'eslint-loader', + enforce: 'pre', + include: [resolve('src'), resolve('test')], + options: { + formatter: require('eslint-friendly-formatter'), + emitWarning: !config.dev.showEslintErrorsInOverlay + } +}) + +module.exports = { + context: path.resolve(__dirname, '../'), + entry: { + app: ['babel-polyfill', './src/main.js'] + }, + output: { + path: config.build.assetsRoot, + filename: '[name].js', + publicPath: process.env.NODE_ENV === 'production' + ? config.build.assetsPublicPath + : config.dev.assetsPublicPath + }, + resolve: { + extensions: ['.js', '.vue', '.json'], + alias: { + 'vue$': 'vue/dist/vue.esm.js', + '@': resolve('src'), + } + }, + module: { + rules: [ + ...(config.dev.useEslint ? [createLintingRule()] : []), + { + test: /\.vue$/, + loader: 'vue-loader', + options: vueLoaderConfig + }, + { + test: /\.js$/, + loader: 'babel-loader', + include: [resolve('src'), resolve('test')] + }, + { + test: /\.svg$/, + loader: 'svg-sprite-loader', + include: [resolve('src/icons')] + }, + { + test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, + loader: 'url-loader', + exclude: [resolve('src/icons')], + options: { + limit: 10000, + name: utils.assetsPath('img/[name].[hash:7].[ext]') + } + }, + { + test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, + loader: 'url-loader', + options: { + limit: 10000, + name: utils.assetsPath('media/[name].[hash:7].[ext]') + } + }, + { + test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, + loader: 'url-loader', + options: { + limit: 10000, + name: utils.assetsPath('fonts/[name].[hash:7].[ext]') + } + } + ] + }, + node: { + // prevent webpack from injecting useless setImmediate polyfill because Vue + // source contains it (although only uses it if it's native). + setImmediate: false, + // prevent webpack from injecting mocks to Node native modules + // that does not make sense for the client + dgram: 'empty', + fs: 'empty', + net: 'empty', + tls: 'empty', + child_process: 'empty' + }, + // 引入外部库, 无需webpack打包处理 + externals: { + echarts: 'echarts', + tinymce: 'tinymce' + } +} diff --git a/mall4v/build/webpack.dev.conf.js b/mall4v/build/webpack.dev.conf.js new file mode 100644 index 0000000..03e9428 --- /dev/null +++ b/mall4v/build/webpack.dev.conf.js @@ -0,0 +1,80 @@ +'use strict' +const utils = require('./utils') +const webpack = require('webpack') +const config = require('../config') +const merge = require('webpack-merge') +const baseWebpackConfig = require('./webpack.base.conf') +const HtmlWebpackPlugin = require('html-webpack-plugin') +const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') +const portfinder = require('portfinder') + +const HOST = process.env.HOST +const PORT = process.env.PORT && Number(process.env.PORT) + +const devWebpackConfig = merge(baseWebpackConfig, { + module: { + rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true }) + }, + // cheap-module-eval-source-map is faster for development + devtool: config.dev.devtool, + + // these devServer options should be customized in /config/index.js + devServer: { + clientLogLevel: 'warning', + historyApiFallback: true, + hot: true, + compress: true, + host: HOST || config.dev.host, + port: PORT || config.dev.port, + open: config.dev.autoOpenBrowser, + overlay: config.dev.errorOverlay + ? { warnings: false, errors: true } + : false, + publicPath: config.dev.assetsPublicPath, + proxy: config.dev.proxyTable, + quiet: true, // necessary for FriendlyErrorsPlugin + watchOptions: { + poll: config.dev.poll, + } + }, + plugins: [ + new webpack.DefinePlugin({ + 'process.env': require('../config/dev.env') + }), + new webpack.HotModuleReplacementPlugin(), + new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update. + new webpack.NoEmitOnErrorsPlugin(), + // https://github.com/ampedandwired/html-webpack-plugin + new HtmlWebpackPlugin({ + filename: 'index.html', + template: 'index.html', + inject: true + }), + ] +}) + +module.exports = new Promise((resolve, reject) => { + portfinder.basePort = process.env.PORT || config.dev.port + portfinder.getPort((err, port) => { + if (err) { + reject(err) + } else { + // publish the new Port, necessary for e2e tests + process.env.PORT = port + // add port to devServer config + devWebpackConfig.devServer.port = port + + // Add FriendlyErrorsPlugin + devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({ + compilationSuccessInfo: { + messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`], + }, + onErrors: config.dev.notifyOnErrors + ? utils.createNotifierCallback() + : undefined + })) + + resolve(devWebpackConfig) + } + }) +}) diff --git a/mall4v/build/webpack.prod.conf.js b/mall4v/build/webpack.prod.conf.js new file mode 100644 index 0000000..fe4aea4 --- /dev/null +++ b/mall4v/build/webpack.prod.conf.js @@ -0,0 +1,148 @@ +'use strict' +const path = require('path') +const utils = require('./utils') +const webpack = require('webpack') +const config = require('../config') +const merge = require('webpack-merge') +const baseWebpackConfig = require('./webpack.base.conf') +const CopyWebpackPlugin = require('copy-webpack-plugin') +const HtmlWebpackPlugin = require('html-webpack-plugin') +const ExtractTextPlugin = require('extract-text-webpack-plugin') +const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') +const UglifyJsPlugin = require('uglifyjs-webpack-plugin') + +const env = process.env.NODE_ENV === 'testing' + ? require('../config/test.env') + : require('../config/prod.env') + +const webpackConfig = merge(baseWebpackConfig, { + module: { + rules: utils.styleLoaders({ + sourceMap: config.build.productionSourceMap, + extract: true, + usePostCSS: true + }) + }, + devtool: config.build.productionSourceMap ? config.build.devtool : false, + output: { + path: config.build.assetsRoot, + filename: utils.assetsPath('js/[name].js'), + chunkFilename: utils.assetsPath('js/[id].js') + }, + plugins: [ + // http://vuejs.github.io/vue-loader/en/workflow/production.html + new webpack.DefinePlugin({ + 'process.env': env + }), + new UglifyJsPlugin({ + uglifyOptions: { + compress: { + warnings: false + } + }, + sourceMap: config.build.productionSourceMap, + parallel: true + }), + // extract css into its own file + new ExtractTextPlugin({ + filename: utils.assetsPath('css/[name].css'), + // set the following option to `true` if you want to extract CSS from + // codesplit chunks into this main css file as well. + // This will result in *all* of your app's CSS being loaded upfront. + allChunks: false, + }), + // Compress extracted CSS. We are using this plugin so that possible + // duplicated CSS from different components can be deduped. + new OptimizeCSSPlugin({ + cssProcessorOptions: config.build.productionSourceMap + ? { safe: true, map: { inline: false } } + : { safe: true } + }), + // generate dist index.html with correct asset hash for caching. + // you can customize output by editing /index.html + // see https://github.com/ampedandwired/html-webpack-plugin + new HtmlWebpackPlugin({ + filename: process.env.NODE_ENV === 'testing' + ? 'index.html' + : config.build.index, + template: 'index.html', + inject: false, + minify: { + removeComments: true, + collapseWhitespace: true, + removeAttributeQuotes: true + // more options: + // https://github.com/kangax/html-minifier#options-quick-reference + }, + // necessary to consistently work with multiple chunks via CommonsChunkPlugin + chunksSortMode: 'dependency' + }), + // keep module.id stable when vender modules does not change + new webpack.HashedModuleIdsPlugin(), + // enable scope hoisting + new webpack.optimize.ModuleConcatenationPlugin(), + // split vendor js into its own file + new webpack.optimize.CommonsChunkPlugin({ + name: 'vendor', + minChunks (module) { + // any required modules inside node_modules are extracted to vendor + return ( + module.resource && + /\.js$/.test(module.resource) && + module.resource.indexOf( + path.join(__dirname, '../node_modules') + ) === 0 + ) + } + }), + // extract webpack runtime and module manifest to its own file in order to + // prevent vendor hash from being updated whenever app bundle is updated + new webpack.optimize.CommonsChunkPlugin({ + name: 'manifest', + minChunks: Infinity + }), + // This instance extracts shared chunks from code splitted chunks and bundles them + // in a separate chunk, similar to the vendor chunk + // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk + new webpack.optimize.CommonsChunkPlugin({ + name: 'app', + async: 'vendor-async', + children: true, + minChunks: 3 + }), + + // copy custom static assets + new CopyWebpackPlugin([ + { + from: path.resolve(__dirname, '../static'), + to: config.build.assetsSubDirectory, + ignore: ['.*'] + } + ]) + ] +}) + +if (config.build.productionGzip) { + const CompressionWebpackPlugin = require('compression-webpack-plugin') + + webpackConfig.plugins.push( + new CompressionWebpackPlugin({ + asset: '[path].gz[query]', + algorithm: 'gzip', + test: new RegExp( + '\\.(' + + config.build.productionGzipExtensions.join('|') + + ')$' + ), + threshold: 10240, + minRatio: 0.8 + }) + ) +} + +if (config.build.bundleAnalyzerReport) { + const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin + webpackConfig.plugins.push(new BundleAnalyzerPlugin({ analyzerMode: 'static' })) +} + +module.exports = webpackConfig diff --git a/mall4v/build/webpack.test.conf.js b/mall4v/build/webpack.test.conf.js new file mode 100644 index 0000000..0d658d9 --- /dev/null +++ b/mall4v/build/webpack.test.conf.js @@ -0,0 +1,32 @@ +'use strict' +// This is the webpack config used for unit tests. + +const utils = require('./utils') +const webpack = require('webpack') +const merge = require('webpack-merge') +const baseWebpackConfig = require('./webpack.base.conf') + +const webpackConfig = merge(baseWebpackConfig, { + // use inline sourcemap for karma-sourcemap-loader + module: { + rules: utils.styleLoaders() + }, + devtool: '#inline-source-map', + resolveLoader: { + alias: { + // necessary to to make lang="scss" work in test when using vue-loader's ?inject option + // see discussion at https://github.com/vuejs/vue-loader/issues/724 + 'scss-loader': 'sass-loader' + } + }, + plugins: [ + new webpack.DefinePlugin({ + 'process.env': require('../config/test.env') + }) + ] +}) + +// no need for app entry during tests +delete webpackConfig.entry + +module.exports = webpackConfig