Spring Boot是一款开箱即用框架,提供各种默认配置来简化项目配置。让我们的Spring应用变的更轻量化、更快的入门。 在主程序执行main函数就可以运行。你也可以打包你的应用为jar并通过使用java -jar来运行你的Web应用。它遵循"约定优先于配置"的原则, 使用SpringBoot只需很少的配置,大部分的时候直接使用默认的配置即可。同时可以与Spring Cloud的微服务无缝结合。
<template> <div> <!--页面区域--> <div class="page-view"> <div class="table-operations"> <a-space> <a-button type="primary" @click="handleAdd">新增</a-button> <a-button @click="handleBatchDelete">批量删除</a-button> <a-input-search addon-before="名称" enter-button @search="onSearch" @change="onSearchChange" /> </a-space> </div> <a-table size="middle" rowKey="id" :loading="data.loading" :columns="columns" :data-source="data.dataList" :scroll="{ x: 'max-content' }" :row-selection="rowSelection" :pagination="{ size: 'default', current: data.page, pageSize: data.pageSize, onChange: (current) => (data.page = current), showSizeChanger: false, showTotal: (total) => `共${total}条数据`, }" > <template #bodyCell="{ text, record, index, column }"> <template v-if="column.key === 'operation'"> <span> <a @click="handleEdit(record)">编辑</a> <a-divider type="vertical" /> <a-popconfirm title="确定删除?" ok-text="是" cancel-text="否" @confirm="confirmDelete(record)"> <a href="#">删除</a> </a-popconfirm> </span> </template> </template> </a-table> </div> <!--弹窗区域--> <div> <a-modal :visible="modal.visile" :forceRender="true" :title="modal.title" width="880px" ok-text="确认" cancel-text="取消" @cancel="handleCancel" @ok="handleOk" > <div> <a-form ref="myform" :label-col="{ style: { width: '80px' } }" :model="modal.form" :rules="modal.rules"> <a-row :gutter="24"> <a-col span="24"> <a-form-item label="宠物名称" name="title"> <a-input placeholder="请输入" v-model:value="modal.form.title" /> </a-form-item> </a-col> <a-col span="24"> <a-form-item label="昵称"> <a-input placeholder="请输入" v-model:value="modal.form.nickname" style="width: 100%" /> </a-form-item> </a-col> <a-col span="12"> <a-form-item label="分类" name="classificationId"> <a-select placeholder="请选择" allowClear :options="modal.cData" :field-names="{ label: 'title', value: 'id' }" v-model:value="modal.form.classificationId" /> </a-form-item> </a-col> <a-col span="12"> <a-form-item label="标签"> <a-select mode="multiple" placeholder="请选择" allowClear v-model:value="modal.form.tags"> <template v-for="item in modal.tagData"> <a-select-option :value="item.id">{{ item.title }}</a-select-option> </template> </a-select> </a-form-item> </a-col> <a-col span="24"> <a-form-item label="封面"> <a-upload-dragger name="file" accept="image/*" :multiple="false" :before-upload="beforeUpload" v-model:file-list="fileList" > <p class="ant-upload-drag-icon"> <template v-if="modal.form.coverUrl"> <img :src="modal.form.coverUrl" style="width: 60px; height: 80px" /> </template> <template v-else> <file-image-outlined /> </template> </p> <p class="ant-upload-text"> 请选择要上传的封面图片 </p> </a-upload-dragger> </a-form-item> </a-col> <a-col span="24"> <a-form-item label="内容简介"> <a-textarea placeholder="请输入" v-model:value="modal.form.description" /> </a-form-item> </a-col> <a-col span="12"> <a-form-item label="性别"> <a-input placeholder="请输入" v-model:value="modal.form.sex" style="width: 100%" /> </a-form-item> </a-col> <a-col span="12"> <a-form-item label="地址" name="price"> <a-input placeholder="请输入" v-model:value="modal.form.address" style="width: 100%" /> </a-form-item> </a-col> <a-col span="12"> <a-form-item label="状态" name="status"> <a-select placeholder="请选择" allowClear v-model:value="modal.form.status"> <a-select-option key="0" value="0">上架</a-select-option> <a-select-option key="1" value="1">下架</a-select-option> </a-select> </a-form-item> </a-col> </a-row> </a-form> </div> </a-modal> </div> </div> </template> <script setup lang="ts"> import { FormInstance, message, SelectProps } from 'ant-design-vue'; import { createApi, listApi, updateApi, deleteApi } from '/@/api/thing'; import { listApi as listClassificationApi } from '/@/api/classification'; import { listApi as listTagApi } from '/@/api/tag'; import { BASE_URL } from '/@/store/constants'; import { FileImageOutlined } from '@ant-design/icons-vue'; const columns = reactive([ { title: '序号', dataIndex: 'index', key: 'index', width: 60, }, { title: '名称', dataIndex: 'title', key: 'title', }, { title: '昵称', dataIndex: 'nickname', key: 'nickname', }, { title: '性别', dataIndex: 'sex', key: 'sex', }, { title: '地址', dataIndex: 'address', key: 'address', }, { title: '简介', dataIndex: 'description', key: 'description', customRender: ({ text, record, index, column }) => (text ? text.substring(0, 10) + '...' : '--'), }, { title: '状态', dataIndex: 'status', key: 'status', customRender: ({ text, record, index, column }) => (text === '0' ? '上架' : '下架'), }, { title: '操作', dataIndex: 'action', key: 'operation', align: 'center', fixed: 'right', width: 140, }, ]); const beforeUpload = (file: File) => { // 改文件名 const fileName = new Date().getTime().toString() + '.' + file.type.substring(6); const copyFile = new File([file], fileName); console.log(copyFile); modal.form.imageFile = copyFile; return false; }; // 文件列表 const fileList = ref<any[]>([]); // 页面数据 const data = reactive({ dataList: [], loading: false, keyword: '', selectedRowKeys: [] as any[], pageSize: 10, page: 1, }); // 弹窗数据源 const modal = reactive({ visile: false, editFlag: false, title: '', cData: [], tagData: [{}], form: { id: undefined, title: undefined, nickname: undefined, sex: undefined, address: undefined, classificationId: undefined, tags: [], repertory: undefined, price: undefined, status: undefined, cover: undefined, coverUrl: undefined, imageFile: undefined, }, rules: { title: [{ required: true, message: '请输入名称', trigger: 'change' }], classificationId: [{ required: true, message: '请选择分类', trigger: 'change' }], repertory: [{ required: true, message: '请输入库存', trigger: 'change' }], status: [{ required: true, message: '请选择状态', trigger: 'change' }], }, }); const myform = ref<FormInstance>(); onMounted(() => { getDataList(); getCDataList(); getTagDataList(); }); const getDataList = () => { data.loading = true; listApi({ keyword: data.keyword, }) .then((res) => { data.loading = false; console.log(res); res.data.forEach((item: any, index: any) => { item.index = index + 1; }); data.dataList = res.data; }) .catch((err) => { data.loading = false; console.log(err); }); }; const getCDataList = () => { listClassificationApi({}).then((res) => { modal.cData = res.data; }); }; const getTagDataList = () => { listTagApi({}).then((res) => { res.data.forEach((item, index) => { item.index = index + 1; }); modal.tagData = res.data; }); }; const onSearchChange = (e: Event) => { data.keyword = e?.target?.value; console.log(data.keyword); }; const onSearch = () => { getDataList(); }; const rowSelection = ref({ onChange: (selectedRowKeys: (string | number)[], selectedRows: DataItem[]) => { console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows); data.selectedRowKeys = selectedRowKeys; }, }); const handleAdd = () => { resetModal(); modal.visile = true; modal.editFlag = false; modal.title = '新增'; // 重置 for (const key in modal.form) { modal.form[key] = undefined; } modal.form.cover = undefined; }; const handleEdit = (record: any) => { resetModal(); modal.visile = true; modal.editFlag = true; modal.title = '编辑'; // 重置 for (const key in modal.form) { modal.form[key] = undefined; } for (const key in record) { if (record[key]) { modal.form[key] = record[key]; } } if (modal.form.cover) { modal.form.coverUrl = BASE_URL + '/api/staticfiles/image/' + modal.form.cover; modal.form.cover = undefined; } }; const confirmDelete = (record: any) => { console.log('delete', record); deleteApi({ ids: record.id }) .then((res) => { getDataList(); }) .catch((err) => { message.error(err.msg || '操作失败'); }); }; const handleBatchDelete = () => { console.log(data.selectedRowKeys); if (data.selectedRowKeys.length <= 0) { console.log('hello'); message.warn('请勾选删除项'); return; } deleteApi({ ids: data.selectedRowKeys.join(',') }) .then((res) => { message.success('删除成功'); data.selectedRowKeys = []; getDataList(); }) .catch((err) => { message.error(err.msg || '操作失败'); }); }; const handleOk = () => { myform.value ?.validate() .then(() => { const formData = new FormData(); if (modal.editFlag) { formData.append('id', modal.form.id); } formData.append('title', modal.form.title); if (modal.form.classificationId) { formData.append('classificationId', modal.form.classificationId); } if (modal.form.tags) { modal.form.tags.forEach(function (value) { if (value) { formData.append('tags[]', value); } }); } if (modal.form.imageFile) { formData.append('imageFile', modal.form.imageFile); } formData.append('description', modal.form.description || ''); formData.append('price', modal.form.price || ''); formData.append('nickname', modal.form.nickname || ''); formData.append('sex', modal.form.sex || ''); formData.append('address', modal.form.address || ''); if (modal.form.status) { formData.append('status', modal.form.status); } if (modal.editFlag) { updateApi(formData) .then((res) => { hideModal(); getDataList(); }) .catch((err) => { console.log(err); message.error(err.msg || '操作失败'); }); } else { createApi(formData) .then((res) => { hideModal(); getDataList(); }) .catch((err) => { console.log(err); message.error(err.msg || '操作失败'); }); } }) .catch((err) => { console.log('不能为空'); }); }; const handleCancel = () => { hideModal(); }; // 恢复表单初始状态 const resetModal = () => { myform.value?.resetFields(); fileList.value = []; }; // 关闭弹窗 const hideModal = () => { modal.visile = false; }; </script> <style scoped lang="less"> .page-view { min-height: 100%; background: #fff; padding: 24px; display: flex; flex-direction: column; } .table-operations { margin-bottom: 16px; text-align: right; } .table-operations > button { margin-right: 8px; } </style>1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.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.82.83.84.85.86.87.88.89.90.91.92.93.94.95.96.97.98.99.100.101.102.103.104.105.106.107.108.109.110.111.112.113.114.115.116.117.118.119.120.121.122.123.124.125.126.127.128.129.130.131.132.133.134.135.136.137.138.139.140.141.142.143.144.145.146.147.148.149.150.151.152.153.154.155.156.157.158.159.160.161.162.163.164.165.166.167.168.169.170.171.172.173.174.175.176.177.178.179.180.181.182.183.184.185.186.187.188.189.190.191.192.193.194.195.196.197.198.199.200.201.202.203.204.205.206.207.208.209.210.211.212.213.214.215.216.217.218.219.220.221.222.223.224.225.226.227.228.229.230.231.232.233.234.235.236.237.238.239.240.241.242.243.244.245.246.247.248.249.250.251.252.253.254.255.256.257.258.259.260.261.262.263.264.265.266.267.268.269.270.271.272.273.274.275.276.277.278.279.280.281.282.283.284.285.286.287.288.289.290.291.292.293.294.295.296.297.298.299.300.301.302.303.304.305.306.307.308.309.310.311.312.313.314.315.316.317.318.319.320.321.322.323.324.325.326.327.328.329.330.331.332.333.334.335.336.337.338.339.340.341.342.343.344.345.346.347.348.349.350.351.352.353.354.355.356.357.358.359.360.361.362.363.364.365.366.367.368.369.370.371.372.373.374.375.376.377.378.379.380.381.382.383.384.385.386.387.388.389.390.391.392.393.394.395.396.397.398.399.400.401.402.403.404.405.406.407.408.409.410.411.412.413.414.415.416.417.418.419.420.421.422.423.424.425.426.427.428.429.430.431.432.433.434.435.436.437.438.439.440.441.442.443.444.445.446.447.448.449.450.451.452.453.454.455.456.457.
每次使用的时候,可以在controller接口上面加入相应的注解来实现权限控制,例如下面加入了@Access(level = AccessLevel.ADMIN)
注解,表明当前接口只能管理员调用。
底层原理实现是通过实现HandlerInterceptorAdapter接口来运行的。参见interceptor文件夹下的AccessInterceptor.java
{ path: '/admin', name: 'admin', redirect: '/admin/thing', component: () => import('/@/views/admin/main.vue'), children: [ { path: 'overview', name: 'overview', component: () => import('/@/views/admin/overview.vue') }, { path: 'order', name: 'order', component: () => import('/@/views/admin/order.vue') }, { path: 'thing', name: 'thing', component: () => import('/@/views/admin/thing.vue') }, { path: 'comment', name: 'comment', component: () => import('/@/views/admin/comment.vue') }, { path: 'user', name: 'user', component: () => import('/@/views/admin/user.vue') }, { path: 'classification', name: 'classification', component: () => import('/@/views/admin/classification.vue') }, { path: 'tag', name: 'tag', component: () => import('/@/views/admin/tag.vue') }, { path: 'ad', name: 'ad', component: () => import('/@/views/admin/ad.vue') }, { path: 'notice', name: 'notice', component: () => import('/@/views/admin/notice.vue') }, { path: 'loginLog', name: 'loginLog', component: () => import('/@/views/admin/login-log.vue') }, { path: 'opLog', name: 'opLog', component: () => import('/@/views/admin/op-log.vue') }, { path: 'errorLog', name: 'errorLog', component: () => import('/@/views/admin/error-log.vue') }, { path: 'sysInfo', name: 'sysInfo', component: () => import('/@/views/admin/sys-info.vue') }, ] },1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.
相关知识
【课程设计/毕业设计】python宠物商城管理系统源码+开发文档
[附源码]JAVA计算机毕业设计宠物领养系统(源码+开题)
基于Java毕业设计宠物论坛设计网站测试视频2021源码+系统+mysql+lw文档+部署软件
Java计算机毕业设计宠物领养系统宠物管理子系统(开题报告+源码+论文)
宠物领养系统宠物管理子系统(程序+开题报告)(开题报告+源码)
Java计算机毕业设计的宠物领养系统(开题报告+源码+论文)
java计算机毕业设计宠物管理系统(开题+程序+论文)
Java计算机毕业设计宠物领养系统(开题报告+源码+论文)
基于SSM的宠物领养系统(附源码)
java毕业设计社区宠物管理与推荐系统(Springboot+mysql+jdk1.8+maven3.39)
网址: 【课程设计/毕业设计】java宠物领养管理系统源码与开发文档 https://m.mcbbbk.com/newsview284643.html
上一篇: 分享一个宠物管理系统的设计思想 |
下一篇: (附源码)Springboot宠 |