Compare commits

..

19 Commits
cyj ... main

@ -1,2 +1,138 @@
# mall4 # 编写的原因
写在前面,很多加入我们群里的人,都会问我们源码在哪里,现在仔细回答一下
1. 我们已经声明了这是一个前后端分离的商城而且分离的很彻底java的后台管理系统不是jsp使用vue写的所以商城的后台管理在vue这个项目 https://gitee.com/gz-yami/mall4v ,启动完java不要访问java的端口启动vue访问vue的端口页面就能看到后台管理就能上商品了
2. 和上面一样的,很多人问,前端的浏览商品的页面在哪里,其实就在这里 https://gitee.com/gz-yami/mall4m
3. 有人会问你是不是将上面两个链接藏起来了上面两个项目的链接都在readme里面写着可是很多人都不读。
4. swagger文档怎么访问不了其实路径是/doc.html
5. 我们开源的刚上线直接申请通过了推荐项目第一天就有100个星星一个月就有1k的星星大家都不是傻的这代码是能用的拜托...后来没怎么维护(整个流程都是好的,整个功能都是好的,都不知道维护啥),现在又开始维护了,星星也没了(如果你悄悄拿去做外包项目,觉得这个项目对你有用,就给个星星呗)
## 先确定我们下载的项目有几个项目
- mall4jj代表javajava项目这里面包含了小程序/后台vue连接需要的接口。
- mall4vv代表vue项目是后台管理员界面使用的前端项目因为前后端分离的
- mall4mm代表mini小程序项目这里的项目是小程序的项目
- mall4uniuni代表uniappH5项目这里的项目是H5的项目
- jvmjava虚拟机啦~
## 1.java开发环境安装
### 1.1开发环境
以下版本是最低要求的!!! 提问问题前请注意开发环境!!
| 工具 | 版本 |
|---------|-------|
| jdk | 17 |
| mysql | 5.7+ |
| redis | 4.0+ |
| nodejs | 14-16 |
| xxl-job | 2.4.0 |
### 1.2 安装jdk + mysql + redis + maven
如果不了解怎么安装jdk的可以参考 [菜鸟教程的java相关](https://www.runoob.com/java/java-environment-setup.html)
- 教程展示的是oracle需要自行搜索openjdk的下载链接下载jdk17版本
如果不了解怎么安装mysql的可以参考 [菜鸟教程的mysql相关](https://www.runoob.com/mysql/mysql-install.html)
如果不了解怎么安装maven的可以参考 [菜鸟教程的maven相关]( https://www.runoob.com/maven/maven-setup.html )
如果对于redis的安装并不了解的可以参考 [菜鸟教程的redis相关](https://www.runoob.com/redis/redis-install.html)
安装相对简单网上也有很多教程这里就不多讲述。安装完按需对redis进行配置后启动redis服务即可。
### 2.启动
- 推荐使用idea安装lombok插件后使用idea导入maven项目
- 将yami_shop.sql导入到mysql中修改`application-dev.yml`更改 datasource.url、user、password
- 通过修改`shop.properties` 修改七牛云、阿里大鱼等信息
- 修改`api.properties` 修改当前接口所在域名,用于支付回调
- 启动redis端口6379
- 通过`WebApplication`启动项目后台接口,`ApiApplication` 启动项目前端接口
- xxl-job定时任务通过github或者gitee下载xxl-job的已经打包好的源码把`XxlJobConfig.class`这个文件的代码注释打开配置yml文件中相关xxl-job配置即可使用
## 3.vue开发环境安装
这是一套正常的vue启动流程。如果你无法理解可能要先学习一下vue...
#### 3.1 安装nodejs
[NodeJS](https://nodejs.org) 项目要求最低 18.12.0,推荐 20.9.0
如果不了解怎么安装nodejs的可以参考 [菜鸟教程的nodejs相关](https://www.runoob.com/nodejs/nodejs-install-setup.html)
#### 3.2 安装依赖启动项目
项目要求使用 [pnpm](https://www.pnpm.cn/) 包管理工具
使用编辑器打开项目,在根目录执行以下命令安装依赖
```bash
pnpm i
```
如果不想使用 pnpm请删除 `package.json` 文件中 `preinstall` 脚本后再进行安装
```json
{
"scripts" : {
"preinstall": "npx only-allow pnpm" // 使用其他包管理工具npm、yarn、cnpm等请删除此命令
}
}
```
H5端和平台端修改文件`.env.production`(生产环境)/ `.env.development`(开发环境)
里面的`VITE_APP_BASE_API`为api接口请求地址 `VITE_APP_RESOURCES_URL`为静态资源文件url
```json
// api接口请求地址
VITE_APP_BASE_API = 'http://127.0.0.1:8085'
// 静态资源文件url
VITE_APP_RESOURCES_URL = 'https://img.mall4j.com/'
```
mall4m小程序端修改文件`utils\config.js`,里面的`domain`为api接口请求地址
注意如果启动uni项目或者小程序默认后台api服务端口号为8086
如果启动后台项目默认后台admin服务端口号为8085请对照仔细填写后再启动如遇401状态码仔细检查端口号是否配置正确
如果后台启动后图形验证码显示“接口验证失败数过多请稍后再试”请F12打开network确定连接的admin服务端口号是否正确ip或域名是否正确
如果有配置nginx还要确认下项目访问路径是否正确可以通过地址+/doc.html来访问接口文档确定是否正确访问到admin服务
运行dev环境
```bash
npm run dev
```
运行dev环境(H5)
```bash
npm run dev:h5
```
## 4.文档
这代码有没有文档呀?
当然有啦你已经下载了在doc这个文件夹上实在不知道我就给链接出来咯
### [https://gitee.com/gz-yami/mall4j/tree/master/doc](https://gitee.com/gz-yami/mall4j/tree/master/doc)

@ -1,4 +1,4 @@
下单简单的分成几个步骤 下单简单的分成几个步骤
1. 用户点击“立即购买”或“购物车-结算”进入到“确认订单”页面 1. 用户点击“立即购买”或“购物车-结算”进入到“确认订单”页面
2. 在“确认订单”页面选择收货地址,优惠券等,重新计算运费、订单价格 2. 在“确认订单”页面选择收货地址,优惠券等,重新计算运费、订单价格

@ -1,94 +1,185 @@
{ {
"globals": { "globals": {
"$t": true, // truefalse
"Component": true,
"ComponentPublicInstance": true, "$t": true, //
"ComputedRef": true,
"Debounce": true, "Component": true, // Vue
"EffectScope": true,
"InjectionKey": true, "ComponentPublicInstance": true, //
"PropType": true,
"Ref": true, "ComputedRef": true, //
"VNode": true,
"clearLoginInfo": true, "Debounce": true, //
"computed": true,
"configDefInfo": true, "EffectScope": true, //
"createApp": true,
"customRef": true, "InjectionKey": true, // 使
"defineAsyncComponent": true,
"defineComponent": true, "PropType": true, // props
"effectScope": true,
"encrypt": true, "Ref": true, //
"flatten": true,
"checkFileUrl": true, "VNode": true, // DOM
"formatConfigInfo": true,
"getCurrentInstance": true, "clearLoginInfo": true, //
"getCurrentScope": true,
"getLevels": true, "computed": true, //
"getUUID": true,
"h": true, "configDefInfo": true, //
"http": true,
"idList": true, "createApp": true, // Vue
"inject": true,
"isAuth": true, "customRef": true, // ref
"isEmail": true,
"isHtmlNull": true, "defineAsyncComponent": true, //
"isMobile": true,
"isPhone": true, "defineComponent": true, //
"isProxy": true,
"isQq": true, "effectScope": true, //
"isReactive": true,
"isReadonly": true, "encrypt": true, //
"isRef": true,
"isURL": true, "flatten": true, //
"markRaw": true,
"nextTick": true, "checkFileUrl": true, // URL
"onActivated": true,
"onBeforeMount": true, "formatConfigInfo": true, //
"onBeforeRouteLeave": true,
"onBeforeRouteUpdate": true, "getCurrentInstance": true, //
"onBeforeUnmount": true,
"onBeforeUpdate": true, "getCurrentScope": true, //
"onDeactivated": true,
"onErrorCaptured": true, "getLevels": true, //
"onMounted": true,
"onRenderTracked": true, "getUUID": true, // UUID
"onRenderTriggered": true,
"onScopeDispose": true, "h": true, // DOM
"onServerPrefetch": true,
"onUnmounted": true, "http": true, // HTTP
"onUpdated": true,
"provide": true, "idList": true, // ID
"reactive": true,
"readonly": true, "inject": true, //
"ref": true,
"resolveComponent": true, "isAuth": true, //
"shallowReactive": true,
"shallowReadonly": true, "isEmail": true, //
"shallowRef": true,
"toRaw": true, "isHtmlNull": true, // HTML
"toRef": true,
"toRefs": true, "isMobile": true, //
"treeDataTranslate": true,
"triggerRef": true, "isPhone": true, //
"unref": true,
"uploadFile": true, "isProxy": true, //
"useAttrs": true,
"useCommonStore": true, "isQq": true, // QQ
"scoreProdStore":true,
"useCssModule": true, "isReactive": true, //
"useCssVars": true,
"useLink": true, "isReadonly": true, //
"useRoute": true,
"useRouter": true, "isRef": true, // ref
"useSlots": true,
"useUserStore": true, "isURL": true, // URL
"useWebConfigStore": true,
"validHtmlLength": true, "markRaw": true, //
"validNoEmptySpace": true,
"watch": true, "nextTick": true, // DOM
"watchEffect": true,
"watchPostEffect": true, "onActivated": true, //
"watchSyncEffect": true
"onBeforeMount": true, //
"onBeforeRouteLeave": true, //
"onBeforeRouteUpdate": true, //
"onBeforeUnmount": true, //
"onBeforeUpdate": true, //
"onDeactivated": true, //
"onErrorCaptured": true, //
"onMounted": true, //
"onRenderTracked": true, //
"onRenderTriggered": true, //
"onScopeDispose": true, //
"onServerPrefetch": true, //
"onUnmounted": true, //
"onUpdated": true, //
"provide": true, //
"reactive": true, //
"readonly": true, //
"ref": true, //
"resolveComponent": true, //
"shallowReactive": true, //
"shallowReadonly": true, //
"shallowRef": true, //
"toRaw": true, //
"toRef": true, // ref
"toRefs": true, // ref
"treeDataTranslate": true, //
"triggerRef": true, // ref
"unref": true, // ref
"uploadFile": true, //
"useAttrs": true, // 使API
"useCommonStore": true, // 使API
"scoreProdStore": true, // 使API
"useCssModule": true, // 使CSSAPI
"useCssVars": true, // 使CSSAPI
"useLink": true, // 使API
"useRoute": true, // 使API
"useRouter": true, // 使API
"useSlots": true, // 使API
"useUserStore": true, // 使API
"useWebConfigStore": true, // 使API
"validHtmlLength": true, // HTML
"validNoEmptySpace": true, //
"watch": true, //
"watchEffect": true, //
"watchPostEffect": true, //
"watchSyncEffect": true //
} }
} }

@ -1,16 +1,33 @@
<!DOCTYPE html> <!DOCTYPE html>
<!-- 声明文档类型为HTML5 -->
<html> <html>
<head> <head>
<!-- 设置文档的字符编码为UTF-8确保正确显示各种语言的文字 -->
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<!-- 指定页面图标favicon通常是一个小图标在浏览器标签上显示 -->
<link rel="icon" href="/favicon.ico" /> <link rel="icon" href="/favicon.ico" />
<!-- 指示IE使用最新的渲染引擎和Chrome Frame如果安装的话来呈现页面 -->
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<!-- 配置移动设备上的视口viewport以确保页面在不同尺寸的屏幕上正确缩放 -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<!-- 引入一个空的script标签ID为qqMap可能是为了之后通过JavaScript动态加载腾讯地图API或其他相关代码 -->
<script id="qqMap" charset="utf-8"></script> <script id="qqMap" charset="utf-8"></script>
<!-- 指定页面使用的渲染器为Webkit这主要用于兼容某些旧版浏览器的行为 -->
<meta name="renderer" content="webkit"> <meta name="renderer" content="webkit">
<!-- 页面标题,这里留空,实际项目中应根据具体需求填写 -->
<title></title> <title></title>
</head> </head>
<body> <body>
<!-- 定义一个div元素ID为app这是单页应用(SPA)中常见的挂载点用于Vue.js或React等框架的应用程序入口 -->
<div id="app"></div> <div id="app"></div>
<!-- 引入主JavaScript文件使用type="module"表明这是一个ES6模块。该文件路径为/src/main.js表示应用程序逻辑的起点 -->
<script type="module" src="/src/main.js"></script> <script type="module" src="/src/main.js"></script>
</body> </body>
</html> </html>

@ -1,22 +1,44 @@
# 定义一个server块它代表一个虚拟主机或站点。
server { server {
# 监听在HTTP标准端口80上这是未加密的HTTP流量的标准端口。
listen 80; listen 80;
# 指定该服务器块响应哪些域名的请求。这里是mini-admin.mall4j.com。
server_name mini-admin.mall4j.com; server_name mini-admin.mall4j.com;
# 开启Gzip压缩功能以减少传输的数据量提高页面加载速度。
gzip on; gzip on;
# 如果存在预压缩的静态资源(如.html.gz则优先提供这些压缩后的资源。
gzip_static on; gzip_static on;
# 定义处理所有请求的location块。
location / { location / {
# 尝试按照顺序查找文件:先找精确匹配的文件路径,然后是目录,最后尝试根路径。
try_files $uri $uri/ /; try_files $uri $uri/ /;
# 设置Web根目录的位置即网站文件存放的目录。
root /usr/share/nginx/html/dist; root /usr/share/nginx/html/dist;
# 当访问根路径时,默认提供的首页文件名。
index index.html; index index.html;
} }
# 当出现404错误找不到页面重定向到指定的404错误页面。
error_page 404 /404.html; error_page 404 /404.html;
# 特别指定当访问路径为/404-light.html时的处理方式。
location = /404-light.html { location = /404-light.html {
# 这里没有额外配置,意味着它将按照默认规则处理此特定路径。
# 使用"="表示精确匹配只有当请求完全符合这个URL时才会触发。
} }
# 对于500系列的服务器错误重定向到指定的50x错误页面。
error_page 500 502 503 504 /50x.html; error_page 500 502 503 504 /50x.html;
# 特别指定当访问路径为/50x.html时的处理方式。
location = /50x.html { location = /50x.html {
# 类似于上面的404-light.html配置这里也没有额外配置。
# "location = /50x.html"确保了只有当请求的是/50x.html时才会应用这个location块。
} }
} }

@ -1,63 +1,79 @@
{ {
"name": "mall4v", "name": "mall4v",
// npm
"private": true, "private": true,
//
"version": "0.0.0", "version": "0.0.0",
// 使ES
"type": "module", "type": "module",
"scripts": { "scripts": {
// 使pnpm
"preinstall": "npx only-allow pnpm", "preinstall": "npx only-allow pnpm",
// 使Vite
"dev": "vite", "dev": "vite",
//
"dev:test": "vite --mode testing", "dev:test": "vite --mode testing",
//
"build": "vite build", "build": "vite build",
//
"build:test": "vite build --mode testing", "build:test": "vite build --mode testing",
// 使eslintsrc.js.vue
"lint": "eslint --ext .js,.vue src", "lint": "eslint --ext .js,.vue src",
// eslint
"lint:fix": "eslint --fix --ext .js,.vue src", "lint:fix": "eslint --fix --ext .js,.vue src",
//
"preview": "vite preview", "preview": "vite preview",
// lint
"lint:staged": "lint-staged" "lint:staged": "lint-staged"
}, },
// Node.jspnpm
"engines": { "engines": {
"node": ">=16", "node": ">=16",
"pnpm": ">=6" "pnpm": ">=6"
}, },
"dependencies": { "dependencies": {
"@element-plus/icons-vue": "2.1.0", //
"@smallwei/avue": "^3.2.22", "@element-plus/icons-vue": "2.1.0", // Element Plus
"axios": "1.3.4", "@smallwei/avue": "^3.2.22", // Avue
"big.js": "6.2.1", "axios": "1.3.4", // HTTP
"browser-image-compression": "2.0.2", "big.js": "6.2.1", //
"crypto-js": "4.1.1", "browser-image-compression": "2.0.2", //
"echarts": "5.4.1", "crypto-js": "4.1.1", //
"element-plus": "2.3.6", "echarts": "5.4.1", //
"element-resize-detector": "1.2.4", "element-plus": "2.3.6", // Element Plus UI
"js-base64": "3.7.5", "element-resize-detector": "1.2.4", // DOM
"lodash": "4.17.21", "js-base64": "3.7.5", // Base64
"moment": "2.29.4", "lodash": "4.17.21", // JavaScript
"pinia": "2.0.33", "moment": "2.29.4", // 使date-fnsdayjs
"qs": "6.11.1", "pinia": "2.0.33", // Vue
"vue": "3.2.47", "qs": "6.11.1", //
"vue-cookies": "1.8.3", "vue": "3.2.47", // Vue
"vue-draggable-next": "2.1.1", "vue-cookies": "1.8.3", // Vuecookies
"vue-router": "4.1.6" "vue-draggable-next": "2.1.1", // Vue
"vue-router": "4.1.6" // Vue
}, },
"devDependencies": { "devDependencies": {
"@babel/eslint-parser": "^7.21.3", // 使
"@vitejs/plugin-vue": "^4.1.0", "@babel/eslint-parser": "^7.21.3", // Babel ESLint
"eslint": "^8.38.0", "@vitejs/plugin-vue": "^4.1.0", // ViteVue
"eslint-config-standard": "^17.0.0", "eslint": "^8.38.0", // ESLint
"eslint-plugin-import": "^2.27.5", "eslint-config-standard": "^17.0.0", // ESLint
"eslint-plugin-n": "^15.7.0", "eslint-plugin-import": "^2.27.5", // ESLintimport/export
"eslint-plugin-promise": "^6.1.1", "eslint-plugin-n": "^15.7.0", // ESLintNode.js
"eslint-plugin-vue": "^9.10.0", "eslint-plugin-promise": "^6.1.1", // ESLintPromise
"eslint-plugin-vue-scoped-css": "^2.4.0", "eslint-plugin-vue": "^9.10.0", // ESLintVue
"lint-staged": "13.2.2", "eslint-plugin-vue-scoped-css": "^2.4.0", // ESLintVueCSS
"sass": "^1.59.3", "lint-staged": "13.2.2", // git
"unplugin-auto-import": "^0.15.1", "sass": "^1.59.3", // Sass
"unplugin-vue-components": "^0.24.1", "unplugin-auto-import": "^0.15.1", // API
"vite": "^4.3.9", "unplugin-vue-components": "^0.24.1", // Vue
"vite-plugin-compression": "^0.5.1", "vite": "^4.3.9", //
"vite-plugin-eslint": "^1.8.1", "vite-plugin-compression": "^0.5.1", // Vite
"vite-plugin-svg-icons": "^2.0.1", "vite-plugin-eslint": "^1.8.1", // ViteESLint
"vue-eslint-parser": "^9.1.1" "vite-plugin-svg-icons": "^2.0.1", // Vite便使SVG
"vue-eslint-parser": "^9.1.1" // VueESLint
}, },
// *.js*.vue
"lint-staged": { "lint-staged": {
"*.{js,vue}": [ "*.{js,vue}": [
"eslint --fix" "eslint --fix"

@ -1,15 +1,29 @@
{ {
"compilerOptions": { "compilerOptions": {
// "commonjs"Node.js
"module": "commonjs", "module": "commonjs",
// JavaScriptECMAScript"es5"
"target": "es5", "target": "es5",
// source mapTypeScriptJavaScript
"sourceMap": true, "sourceMap": true,
// .d.ts
"skipLibCheck": true "skipLibCheck": true
}, },
// node_modulesTypeScript
"exclude": [ "exclude": [
"node_modules" "node_modules"
], ],
//
"include": [ "include": [
// TypeScript
"src/auto-import/components.d.ts", "src/auto-import/components.d.ts",
// TypeScript
"src/auto-import/imports.d.ts" "src/auto-import/imports.d.ts"
] ]
} }

@ -1,4 +1,3 @@
```java ```java
/* /*

@ -7,11 +7,29 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
/** /**
* ResourceServerAdapter DefaultAuthConfigAdapter
*
* 使 Spring @Component 便 Spring Bean
*
* @author * @author
* @date 2022/3/28 14:57 * @date 2022/3/28 14:57
*/ */
@Component @Component
public class ResourceServerAdapter extends DefaultAuthConfigAdapter { public class ResourceServerAdapter extends DefaultAuthConfigAdapter {
/**
* EXCLUDE_PATH List
*
* - /webjars/**WebJars
* - /swagger/**Swagger API
* - /v3/api-docs/**Swagger API JSON
* - /doc.htmlSwagger
* - /swagger-ui.htmlSwagger UI
* - /swagger-resources/**Swagger
* - /captcha/**
* - /adminLogin
* - /mall4j/img/** mall4j
*/
public static final List<String> EXCLUDE_PATH = Arrays.asList( public static final List<String> EXCLUDE_PATH = Arrays.asList(
"/webjars/**", "/webjars/**",
"/swagger/**", "/swagger/**",
@ -23,6 +41,13 @@ public class ResourceServerAdapter extends DefaultAuthConfigAdapter {
"/adminLogin", "/adminLogin",
"/mall4j/img/**"); "/mall4j/img/**");
/**
* excludePathPatterns
* 访
* 便访
*
* @return List
*/
@Override @Override
public List<String> excludePathPatterns() { public List<String> excludePathPatterns() {
return EXCLUDE_PATH; return EXCLUDE_PATH;

@ -10,11 +10,13 @@
package com.yami.shop.security.admin.model; package com.yami.shop.security.admin.model;
import lombok.Data; import lombok.Data;
import java.util.Set; import java.util.Set;
/** /**
* * YamiSysUser
* 使 Lombok @Data gettersetterequalshashCode toString
*
* *
* @author * @author
*/ */
@ -22,16 +24,34 @@ import java.util.Set;
public class YamiSysUser { public class YamiSysUser {
/** /**
* ID * ID
*
*/ */
private Long userId; private Long userId;
/**
*
* true使
* false使
*/
private boolean enabled; private boolean enabled;
/**
*
* "READ", "WRITE", "DELETE"
*
*/
private Set<String> authorities; private Set<String> authorities;
/**
*
*
*/
private String username; private String username;
/**
* ID
* 便
*/
private Long shopId; private Long shopId;
} }

@ -15,6 +15,9 @@ import com.yami.shop.security.common.util.AuthUserContext;
import lombok.experimental.UtilityClass; import lombok.experimental.UtilityClass;
/** /**
* SecurityUtils com.yami.shop.security.admin.util
* getSysUser()
* 使 Lombok @UtilityClass
* *
* @author LGH * @author LGH
*/ */
@ -22,6 +25,8 @@ import lombok.experimental.UtilityClass;
public class SecurityUtils { public class SecurityUtils {
/** /**
* *
*
* @return
*/ */
public YamiSysUser getSysUser() { public YamiSysUser getSysUser() {
UserInfoInTokenBO userInfoInTokenBO = AuthUserContext.get(); UserInfoInTokenBO userInfoInTokenBO = AuthUserContext.get();
@ -35,4 +40,3 @@ public class SecurityUtils {
return details; return details;
} }
} }

Loading…
Cancel
Save