1. VUE多环境配置
使用Vue CLI 3+的vue.config.js文件来配置多个环境
1.1 安装Vue CLI
npm install -g @vue/cli
1.2 package.json引入 Vue CLI
{
"name": "tool-vue",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
#修改为vue-cli-service 启动项目
"dev": "vue-cli-service serve --mode development",
"build": "vue-cli-service build --mode production",
"preview": "vite preview"
},
"dependencies": {
"axios": "^1.7.7",
"element-plus": "^2.8.6",
"vue": "^3.5.12",
"vue-router": "^4.4.5"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.1.4",
"vite": "^5.4.8",
#引入vue/cli-service
"@vue/cli-service": "^4.5.0"
}
}
重新install
npm install
1.3 创建多环境配置文件
创建.env.development
# 开发环境配置
ENV = 'development'
VUE_APP_BASE_API = 'http://localhost:8888/tool-api'
创建.env.production
# 生产环境配置
ENV = 'production'
VUE_APP_BASE_API = '/tool-api'
2. Java 统一封装返回结果和异常情况
2.1 创建返回状态码类HttpStatus
package com.tool.tooladmin.config.result;
/**
* 返回状态码
*/
public class HttpStatus {
/**
* 操作成功
*/
public static final int SUCCESS = 200;
/**
* 对象创建成功
*/
public static final int CREATED = 201;
/**
* 请求已经被接受
*/
public static final int ACCEPTED = 202;
/**
* 操作已经执行成功,但是没有返回数据
*/
public static final int NO_CONTENT = 204;
/**
* 资源已被移除
*/
public static final int MOVED_PERM = 301;
/**
* 重定向
*/
public static final int SEE_OTHER = 303;
/**
* 资源没有被修改
*/
public static final int NOT_MODIFIED = 304;
/**
* 参数列表错误(缺少,格式不匹配)
*/
public static final int BAD_REQUEST = 400;
/**
* 未授权
*/
public static final int UNAUTHORIZED = 401;
/**
* 访问受限,授权过期
*/
public static final int FORBIDDEN = 403;
/**
* 资源,服务未找到
*/
public static final int NOT_FOUND = 404;
/**
* 不允许的http方法
*/
public static final int BAD_METHOD = 405;
/**
* 资源冲突,或者资源被锁
*/
public static final int CONFLICT = 409;
/**
* 不支持的数据,媒体类型
*/
public static final int UNSUPPORTED_TYPE = 415;
/**
* 系统内部错误
*/
public static final int ERROR = 500;
/**
* 接口未实现
*/
public static final int NOT_IMPLEMENTED = 501;
/**
* 系统警告消息
*/
public static final int WARN = 601;
}
2.2 创建响应信息主体
package com.tool.tooladmin.config.result;
import java.io.Serializable;
/**
* 响应信息主体
*/
public class R<T> implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 成功
*/
public static final int SUCCESS = HttpStatus.SUCCESS;
/**
* 失败
*/
public static final int FAIL = HttpStatus.ERROR;
private int code;
private String msg;
private T data;
public static <T> R<T> ok() {
return restResult(null, SUCCESS, "操作成功");
}
public static <T> R<T> ok(T data) {
return restResult(data, SUCCESS, "操作成功");
}
public static <T> R<T> ok(T data, String msg) {
return restResult(data, SUCCESS, msg);
}
public static <T> R<T> fail() {
return restResult(null, FAIL, "操作失败");
}
public static <T> R<T> fail(String msg) {
return restResult(null, FAIL, msg);
}
public static <T> R<T> fail(T data) {
return restResult(data, FAIL, "操作失败");
}
public static <T> R<T> fail(T data, String msg) {
return restResult(data, FAIL, msg);
}
public static <T> R<T> fail(int code, String msg) {
return restResult(null, code, msg);
}
private static <T> R<T> restResult(T data, int code, String msg) {
R<T> apiResult = new R<>();
apiResult.setCode(code);
apiResult.setData(data);
apiResult.setMsg(msg);
return apiResult;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public static <T> Boolean isError(R<T> ret) {
return !isSuccess(ret);
}
public static <T> Boolean isSuccess(R<T> ret) {
return R.SUCCESS == ret.getCode();
}
}
2.3 创建操作消息提醒AjaxResult
package com.tool.tooladmin.config.result;
import java.util.HashMap;
import java.util.Objects;
/**
* 操作消息提醒
*/
public class AjaxResult extends HashMap<String, Object> {
private static final long serialVersionUID = 1L;
/**
* 状态码
*/
public static final String CODE_TAG = "code";
/**
* 返回内容
*/
public static final String MSG_TAG = "msg";
/**
* 数据对象
*/
public static final String DATA_TAG = "data";
/**
* 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。
*/
public AjaxResult() {
}
/**
* 初始化一个新创建的 AjaxResult 对象
*
* @param code 状态码
* @param msg 返回内容
*/
public AjaxResult(int code, String msg) {
super.put(CODE_TAG, code);
super.put(MSG_TAG, msg);
}
/**
* 初始化一个新创建的 AjaxResult 对象
*
* @param code 状态码
* @param msg 返回内容
* @param data 数据对象
*/
public AjaxResult(int code, String msg, Object data) {
super.put(CODE_TAG, code);
super.put(MSG_TAG, msg);
if (data != null) {
super.put(DATA_TAG, data);
}
}
/**
* 返回成功消息
*
* @return 成功消息
*/
public static AjaxResult success() {
return AjaxResult.success("操作成功");
}
/**
* 返回成功数据
*
* @return 成功消息
*/
public static AjaxResult success(Object data) {
return AjaxResult.success("操作成功", data);
}
/**
* 返回成功消息
*
* @param msg 返回内容
* @return 成功消息
*/
public static AjaxResult success(String msg) {
return AjaxResult.success(msg, null);
}
/**
* 返回成功消息
*
* @param msg 返回内容
* @param data 数据对象
* @return 成功消息
*/
public static AjaxResult success(String msg, Object data) {
return new AjaxResult(HttpStatus.SUCCESS, msg, data);
}
/**
* 返回警告消息
*
* @param msg 返回内容
* @return 警告消息
*/
public static AjaxResult warn(String msg) {
return AjaxResult.warn(msg, null);
}
/**
* 返回警告消息
*
* @param msg 返回内容
* @param data 数据对象
* @return 警告消息
*/
public static AjaxResult warn(String msg, Object data) {
return new AjaxResult(HttpStatus.WARN, msg, data);
}
/**
* 返回错误消息
*
* @return 错误消息
*/
public static AjaxResult error() {
return AjaxResult.error("操作失败");
}
/**
* 返回错误消息
*
* @param msg 返回内容
* @return 错误消息
*/
public static AjaxResult error(String msg) {
return AjaxResult.error(msg, null);
}
/**
* 返回错误消息
*
* @param msg 返回内容
* @param data 数据对象
* @return 错误消息
*/
public static AjaxResult error(String msg, Object data) {
return new AjaxResult(HttpStatus.ERROR, msg, data);
}
/**
* 返回错误消息
*
* @param code 状态码
* @param msg 返回内容
* @return 错误消息
*/
public static AjaxResult error(int code, String msg) {
return new AjaxResult(code, msg, null);
}
/**
* 是否为成功消息
*
* @return 结果
*/
public boolean isSuccess() {
return Objects.equals(HttpStatus.SUCCESS, this.get(CODE_TAG));
}
/**
* 是否为警告消息
*
* @return 结果
*/
public boolean isWarn() {
return Objects.equals(HttpStatus.WARN, this.get(CODE_TAG));
}
/**
* 是否为错误消息
*
* @return 结果
*/
public boolean isError() {
return Objects.equals(HttpStatus.ERROR, this.get(CODE_TAG));
}
/**
* 方便链式调用
*
* @param key 键
* @param value 值
* @return 数据对象
*/
@Override
public AjaxResult put(String key, Object value) {
super.put(key, value);
return this;
}
}
2.4 创建web层通用数据处理BaseController
/**
* 返回成功
*/
public AjaxResult success() {
return AjaxResult.success();
}
/**
* 返回失败消息
*/
public AjaxResult error() {
return AjaxResult.error();
}
/**
* 返回成功消息
*/
public AjaxResult success(String message) {
return AjaxResult.success(message);
}
/**
* 返回成功消息
*/
public AjaxResult success(Object data) {
return AjaxResult.success(data);
}
/**
* 返回失败消息
*/
public AjaxResult error(String message) {
return AjaxResult.error(message);
}
/**
* 返回警告消息
*/
public AjaxResult warn(String message) {
return AjaxResult.warn(message);
}
/**
* 响应返回结果
*
* @param rows 影响行数
* @return 操作结果
*/
protected AjaxResult toAjax(int rows) {
return rows > 0 ? AjaxResult.success() : AjaxResult.error();
}
/**
* 响应返回结果
*
* @param result 结果
* @return 操作结果
*/
protected AjaxResult toAjax(boolean result) {
return result ? success() : error();
}
2.5 修改testController
package com.tool.tooladmin.algorithm;
import com.tool.tooladmin.config.result.BaseController;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
/**
* test
*
*/
@RestController
@RequestMapping("/test")
public class testController extends BaseController {
@GetMapping("/test")
public Map<String, Object> test() {
Map<String, Object> map = new HashMap<>();
map.put("msg", "test");
return success(map);
}
}
3. 动态展示网页标题
使用Vue Router 动态设置
import { createRouter, createWebHistory } from 'vue-router';
import Home from '../views/Home.vue';
import About from '../views/About.vue';
const routes = [
{
path: '/:pathMatch(.*)*', // 通配符路由
name: 'Error404',
component: Error404,
meta: { title: '404 - 页面未找到' },
},
{
path: '/',
name: 'Home',
component: Home,
meta: { title: '首页' }
},
{
path: '/about',
name: 'About',
component: About,
meta: { title: '关于' }
}
];
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
});
router.beforeEach((to, from, next) => {
document.title = to.meta.title || '默认标题';
next();
});
export default router;
4. 封装消息弹窗
4.1 创建 message.js 文件
// message.js
import { ElMessage } from 'element-plus';
export const successMessage = (message) => {
ElMessage({
message: message,
type: 'success',
plain: true,
});
};
export const errorMessage = (message) => {
ElMessage({
message: message,
type: 'error',
plain: true,
});
};
export const warningMessage = (message) => {
ElMessage({
message: message,
type: 'warning',
plain: true,
});
}
export const infoMessage = (message) => {
ElMessage({
message: message,
type: 'info',
plain: true,
});
}
4.2 引用
import {errorMessage, successMessage} from "@/utils/message.js";
errorMessage('请输入错误信息');
5. 优化菜单栏
5.1 新建MenuItem.vue,菜单树
封装菜单树形页面
<template>
<div>
<el-menu-item v-if="!item.children || item.children.length === 0" :index="item.index">
<span>{{ item.title }}</span>
</el-menu-item>
<el-sub-menu v-else :index="item.index">
<template #title>
<span>{{ item.title }}</span>
</template>
<menu-item v-for="child in item.children" :key="child.id" :item="child" />
</el-sub-menu>
</div>
</template>
<script setup>
import { defineProps } from 'vue';
const props = defineProps({
item: {
type: Object,
required: true
}
});
</script>
5.2 优化SideBar.vue
<template>
<h4 class="side-bar-title">菜单</h4>
<el-menu ref="menu" :router="true" :default-active="activeIndex" class="el-menu-vertical-demo">
<menu-item v-for="item in menuTree" :key="item.id" :item="item" />
</el-menu>
</template>
<style scoped>
.el-menu-vertical-demo {
height: 95%;
}
.side-bar-title {
text-align: left;
font-weight: bold;
padding: 10px 0 10px 0px;
}
</style>
<script setup>
import { ref, onMounted, watch } from 'vue';
import {useRoute} from 'vue-router';
import { ElMenu } from 'element-plus';
import MenuItem from './MenuItem.vue';
import {getMenuTree} from "@/basic/basic.js";
const route = useRoute();
const activeIndex = ref(route.path);
const menuTree = ref([]);
const fetchMenuTree = async () => {
try {
const response = await getMenuTree();
menuTree.value = response.data;
} catch (error) {
console.error('Failed to fetch menu tree:', error);
}
};
onMounted(() => {
fetchMenuTree();
});
watch(() => route.path, (newPath) => {
activeIndex.value = newPath;
});
</script>
5.3 引入菜单查询js
import http from '@/utils/http'
export function getMenuTree() {
return http({
url: '/menu/getMenuTree',
method: 'get',
})
}
5.4 新增菜单查询接口
bubbleSort的index写法一定要是“/bubbleSort”,只写“bubbleSort”也能访问到,但是菜单识别不到
package com.tool.tooladmin.admin.menu.controller;
import com.tool.tooladmin.admin.menu.domain.Menu;
import com.tool.tooladmin.config.result.AjaxResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/menu")
public class MenuController {
@GetMapping("/getMenuTree")
public AjaxResult getMenuTree() {
List<Menu> menuList = getMenuList();
List<Menu> menuTree = buildMenuTree(menuList);
// 将menuList转换为树形结构
return AjaxResult.success(menuTree);
}
public List<Menu> getMenuList(){
List<Menu> menuList = new ArrayList<>();
menuList.add(new Menu(1L, 0L, "首页", "/",null, 0));
menuList.add(new Menu(2L, 0L, "算法", "/2",null, 0));
menuList.add(new Menu(3L, 2L, "排序算法", "/3",null, 0));
menuList.add(new Menu(4L, 3L, "冒泡排序", "/bubbleSort",null, 0));
return menuList;
}
private List<Menu> buildMenuTree(List<Menu> menuList) {
Map<Long, Menu> menuMap = new HashMap<>();
List<Menu> rootMenus = new ArrayList<>();
for (Menu menu : menuList) {
menuMap.put(menu.getId(), menu);
}
for (Menu menu : menuList) {
if (menu.getParentId() == 0) {
rootMenus.add(menu);
} else {
Menu parentMenu = menuMap.get(menu.getParentId());
if (parentMenu != null) {
parentMenu.getChildren().add(menu);
}
}
}
return rootMenus;
}
}
菜单树实体类
package com.tool.tooladmin.admin.menu.domain;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class Menu {
private long id;
private long parentId;
private String title;
private String index;
private String icon;
private long sort;
private List<Menu> children;
public Menu() {
super();
}
public Menu(long id, long parentId, String title, String index, String icon, long sort) {
this.id = id;
this.parentId = parentId;
this.title = title;
this.index = index;
this.icon = icon;
this.sort = sort;
this.children = new ArrayList<>();
}
}
6. 引入MarkdownItVue
6.1 安装 vue3-markdown-it 和其依赖
npm install vue3-markdown-it markdown-it
6.2 配置全局
在mian.js引入配置
import './assets/main.css'
import router from './router';
import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css';
import { createApp } from 'vue'
import App from './App.vue'
import http from './utils/http'; // 引入封装的http请求
import MarkdownItVue from 'vue3-markdown-it';
// createApp(App).mount('#app')
const app = createApp(App);
// 设置网页标题
document.title = '工具';
//使用路由器
app.use(router);
//使用ElementPlus
app.use(ElementPlus);
//使用MarkdownItVue
app.use( MarkdownItVue);
//将http请求挂载到全局
app.config.globalProperties.$http = http;
app.mount('#app');
6.3 使用MD
<template>
<div>
<h1>Markdown 示例</h1>
<vue3-markdown-it :source="markdownContent" />
</div>
</template>
<script>
import {ref} from 'vue';
const markdownContent = ref(`# Hello, Vue 3 Markdown!
This is a simple Markdown editor example.`);
</script>
<style scoped>
/* 自定义样式 */
</style>