域名不变 新网站各种网址大全

diannao/2026/1/21 3:15:06/文章来源:
域名不变 新网站,各种网址大全,网站前台和后台,wordpress 提问前端项目创建 准备工作 nodejs安装 vue cli安装 vue create frontend 最后一个y的话 它会保存 方便下次创建项目 我这是手快敲错了 随自己 前端项目组件及作用 Element-UI引入 安装 npm i element-ui -S main.js中引入 清空路口App.vue 清空Home页面 随便写个按钮 原因…前端项目创建 准备工作   nodejs安装   vue cli安装 vue create frontend 最后一个y的话 它会保存  方便下次创建项目  我这是手快敲错了 随自己 前端项目组件及作用 Element-UI引入 安装 npm i element-ui -S main.js中引入 清空路口App.vue 清空Home页面 随便写个按钮 原因 全局样式控制 因为Element-UI带有一些默认样式,有时我们需要创建全局的样式控制(清空ElementUI样式)需要自定义一些样式等 一般在assets中创建 global.css 在main.js中引入 对比 Vue管理系统页面布局 容器布局 左侧菜单 点击菜单进行路由跳转 例如 我新建一个视图 配置路由 表格(编辑删除) 路由 视图 搜索 新增 (el-input) 全局配置UI按钮大小 全局表格头居中data居中 表格数据分页 后台搭建 server:port: 8085spring:application:name: backendredis:##redis 单机环境配置##将docker脚本部署的redis服务映射为宿主机ip##生产环境推荐使用阿里云高可用redis服务并设置密码host: 127.0.0.1port: 6379database: 0password: 123456ssl: false##redis 集群环境配置#cluster:# nodes: 127.0.0.1:7001,127.0.0.1:7002,127.0.0.1:7003# commandTimeout: 5000datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://xxxxx:3306/springboot?useSSLfalseuseUnicodetruecharacterEncodingUTF-8autoReconnecttrueserverTimezoneGMT%2B8useCursorFetchtrueusername: xxxxxpassword: xxxxxxmybatis:type-aliases-package: com.example.backend.pojomapper-locations: classpath:mappers/*Mapperconfiguration:map-underscore-to-camel-case: true logging:level:com.example.backend.mapper: debug 前端发送axios调用接口 安装axios npm install axios 封装axios请求 import axios from axios import router from ../router; //创建axios实例 const request axios.create({baseURL: http://localhost:8085,timeout: 5000 })// request 拦截器// 可以自动发送请求前进行一些处理// 比如统一加token, 对请求参数统一加密request.interceptors.request.use(config {config.headers[Content-Type] application/json;charsetutf-8;// 从sessionStorage中获取tokenconst token sessionStorage.getItem(token);if (token) {config.headers[token] token; // 如果token存在让每个请求头携带token} else {// token不存在重定向到登录页面window.location.href /; // 或使用 Vue Router的 this.$router.push(/login)//this.$router.push(/)}return config;}, error {return Promise.reject(error);});// response 拦截器// 可以在接口响应后统一处理结果request.interceptors.response.use(response {let res response.data;// 若返回的是字符串则转换成jsonif (typeof res string) {res res ? JSON.parse(res) : res//将JSON字符串转JS对象 方便点出来}return res;},error {console.log(err error) // for debugreturn Promise.reject(error)});export default request;//导出 其他页面引用 对表格页面进行修改 改成动态数据 引入axios请求 按条件查询 添加清空按钮 分页查询 前端代码 后端引入分页依赖pagehelp 实体类 持久层 业务层 控制器 返回结果类 新增和编辑 注意后面用用户登录  没有对name进行唯一约束  编码也没有   这个注意下 Dialog对话框 message消息提示 前端新增和编辑代码  template!-- 需要有一个根div --divdiv stylemargin-bottom: 20px;el-input stylewidth: 300px; v-modelparams.name placeholder请输入姓名/el-inputel-input stylewidth: 300px; margin-left: 20px; v-modelparams.phone placeholder请输入电话/el-inputel-button stylemargin-left: 20px; clickfindBySearch(1)查询/el-buttonel-button stylemargin-left: 20px; clickreset清空/el-buttonbrel-button typeprimary stylemargin-top: 20px; clickaddForm新增/el-buttonhr //divdivel-table :datatableData stylewidth: 100%el-table-column propname label姓名 width180/el-table-columnel-table-column proppassword label密码 width180/el-table-columnel-table-column propage label年龄/el-table-columnel-table-column propphone label电话/el-table-columnel-table-column label操作template slot-scopeaaael-button typeprimary clickedit(aaa.row)编辑/el-buttonel-button typedanger删除/el-button/template/el-table-column/el-table/divdivel-pagination stylemargin-top: 20px; size-changehandleSizeChangecurrent-changehandleCurrentChange :current-pageparams.pageNum :page-sizes[5, 10, 15, 20]:page-sizeparams.pageSize layouttotal, sizes, prev, pager, next, jumper :totaltotalNum/el-pagination/divdivel-dialog :titledialogTitle :visible.syncdialogFormVisible closeresetFormel-form :modelformel-form-item label姓名 :label-widthformLabelWidthel-input v-modelform.name autocompleteoff/el-input/el-form-itemel-form-item label年龄 :label-widthformLabelWidthel-input v-modelform.age autocompleteoff/el-input/el-form-itemel-form-item label密码 :label-widthformLabelWidthel-input v-modelform.password autocompleteoff/el-input/el-form-itemel-form-item label电话 :label-widthformLabelWidthel-input v-modelform.phone autocompleteoff/el-input/el-form-item/el-formdiv slotfooter classdialog-footerel-button clickdialogFormVisible false取 消/el-buttonel-button typeprimary clicksubmit :disabledisSubmitting确 定/el-button/div/el-dialog/div/div /template script import request from /api/HttpRequest export default {name: AdminView,data() {return {dialogFormVisible: false,isEdit: false, // 标志是编辑状态还是新增状态dialogTitle: , // 对话框标题params: {name: ,phone: ,pageNum: 1,pageSize: 5,},totalNum: 0,tableData: [],form: {},formLabelWidth: 120px,isSubmitting: false //提交标志}},created() {this.findBySearch()},methods: {resetForm() {this.form {name: ,password: ,age: ,phone: };},reset() {this.params.name this.params.phone this.findBySearch()},findBySearch(val) {if (val 1) {this.params.pageNum 1this.params.pageSize 5}request.get(/test/search, {params: this.params}).then(res {if (res.code 200) {this.tableData res.data.listthis.totalNum res.data.total} else {}})},addForm() {this.resetForm(); // 重置表单this.isEdit false; // 设置为新增模式this.dialogTitle 新增管理员信息; // 设置对话框标题this.dialogFormVisible true; // 显示对话框},edit(row) {this.isEdit true; // 设置为编辑模式this.dialogTitle 更新管理员信息; // 设置对话框标题this.form Object.assign({}, row); // 深拷贝行数据到表单//this.formrowthis.dialogFormVisible true; // 显示对话框},submit() {if (this.isSubmitting) return;this.isSubmitting true;const api this.isEdit ? /test/updateUser : /test/adduser;request.post(api, this.form).then(res {if (res.code 200) {this.$message({message: this.isEdit ? 更新成功 : 新增成功,type: success});this.dialogFormVisible false;this.resetForm()this.findBySearch(1);} else {this.$message.error(出错了,请联系管理员);}}).catch(error {console.error(请求失败, error);this.$message.error(网络错误请稍后再试);}).finally(() {this.isSubmitting false;});},handleSizeChange(val) {this.params.pageSize valthis.findBySearch()},handleCurrentChange(val) {this.params.pageNum valthis.findBySearch()}}, } /script 后端新增和编辑代码  其实新增和编辑可以用一个接口  更具实体类id是否为null既可以判断是新增操作还是更新操作 持久层 package com.example.backend.mapper;import com.example.backend.pojo.User; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update;import java.util.List;/*** author hrui* date 2024/3/13 5:28*/ public interface UserMapper{Select(select * from t_user)ListUser selectAllUser();Select({script select * from t_user whereif testname!null and name!\\ // and name#{name}and name like concat(%,#{name},%)/ifif testphone!null and phone!\\ and phone#{phone}/if/where/script})ListUser selectUserByCondition(User user);Insert({script,insert into t_user,trim prefix( suffix) suffixOverrides,,id,,if testname!null and name!\\,name,,/if,if testpassword!null and password!\\,password,,/if,if testage!null and age!\\,age,,/if,if testphone!null and phone!\\,phone,,/if,/trim,values,trim prefix( suffix) suffixOverrides,,null,,if testname!null and name!\\,#{name},,/if,if testpassword!null and password!\\,#{password},,/if,if testage!null and age!\\,#{age},,/if,if testphone!null and phone!\\,#{phone},,/if,/trim,/script})int insertUser(User user);Update({script,UPDATE t_user,set,if testname!null and name!\\,name #{name},,/if,if testpassword!null and password!\\,password #{password},,/if,if testage!null and age!\\,age #{age},,/if,if testphone!null and phone!\\,phone #{phone},,/if,/set,WHERE id #{id},/script})int updateUser(User user);}删除 删除操作一般需要提示用户确认 删除代码 template!-- 需要有一个根div --divdiv stylemargin-bottom: 20px;el-input stylewidth: 300px; v-modelparams.name placeholder请输入姓名/el-inputel-input stylewidth: 300px; margin-left: 20px; v-modelparams.phone placeholder请输入电话/el-inputel-button stylemargin-left: 20px; clickfindBySearch(1)查询/el-buttonel-button stylemargin-left: 20px; clickreset清空/el-buttonbrel-button typeprimary stylemargin-top: 20px; clickaddForm新增/el-buttonhr //divdivel-table :datatableData stylewidth: 100%el-table-column propname label姓名 width180/el-table-columnel-table-column proppassword label密码 width180/el-table-columnel-table-column propage label年龄/el-table-columnel-table-column propphone label电话/el-table-columnel-table-column label操作template slot-scopescopeel-button typeprimary clickedit(scope.row)编辑/el-buttonel-popconfirm title确定要删除这条记录吗 confirmdeleteRow(scope.row.id) confirm-button-text确定cancel-button-text取消template #referenceel-button typedanger stylemargin-left: 10px;删除/el-button/template/el-popconfirm/template/el-table-column/el-table/divdivel-pagination stylemargin-top: 20px; size-changehandleSizeChangecurrent-changehandleCurrentChange :current-pageparams.pageNum :page-sizes[5, 10, 15, 20]:page-sizeparams.pageSize layouttotal, sizes, prev, pager, next, jumper :totaltotalNum/el-pagination/divdivel-dialog :titledialogTitle :visible.syncdialogFormVisible closeresetFormel-form :modelformel-form-item label姓名 :label-widthformLabelWidthel-input v-modelform.name autocompleteoff/el-input/el-form-itemel-form-item label年龄 :label-widthformLabelWidthel-input v-modelform.age autocompleteoff/el-input/el-form-itemel-form-item label密码 :label-widthformLabelWidthel-input v-modelform.password autocompleteoff/el-input/el-form-itemel-form-item label电话 :label-widthformLabelWidthel-input v-modelform.phone autocompleteoff/el-input/el-form-item/el-formdiv slotfooter classdialog-footerel-button clickdialogFormVisible false取 消/el-buttonel-button typeprimary clicksubmit :disabledisSubmitting确 定/el-button/div/el-dialog/div/div /template script import request from /api/HttpRequest export default {name: AdminView,data() {return {dialogFormVisible: false,isEdit: false, // 标志是编辑状态还是新增状态dialogTitle: , // 对话框标题params: {name: ,phone: ,pageNum: 1,pageSize: 5,},totalNum: 0,tableData: [],form: {},formLabelWidth: 120px,isSubmitting: false //提交标志}},created() {this.findBySearch()},methods: {resetForm() {this.form {name: ,password: ,age: ,phone: };},reset() {this.params.name this.params.phone this.findBySearch()},findBySearch(val) {if (val 1) {this.params.pageNum 1this.params.pageSize 5}request.get(/test/search, {params: this.params}).then(res {if (res.code 200) {this.tableData res.data.listthis.totalNum res.data.total} else {}})},addForm() {this.resetForm(); // 重置表单this.isEdit false; // 设置为新增模式this.dialogTitle 新增管理员信息; // 设置对话框标题this.dialogFormVisible true; // 显示对话框},edit(row) {this.isEdit true; // 设置为编辑模式this.dialogTitle 更新管理员信息; // 设置对话框标题this.form Object.assign({}, row); // 深拷贝行数据到表单//this.formrowthis.dialogFormVisible true; // 显示对话框},deleteRow(id) {// 这里应该调用API来删除row代表的数据// 例如this.isSubmitting true;request.delete(/test/deleteUser/${id}).then(res {if (res.code 200) {this.$message.success(删除成功);this.findBySearch(); // 重新加载当前页的数据或者根据需要更新视图} else {this.$message.error(删除失败请稍后再试);}}).catch(error {console.error(请求失败, error);this.$message.error(网络错误请稍后再试);}).finally(() {this.isSubmitting false;});},submit() {if (this.isSubmitting) return;this.isSubmitting true;const api this.isEdit ? /test/updateUser : /test/adduser;request.post(api, this.form).then(res {if (res.code 200) {this.$message({message: this.isEdit ? 更新成功 : 新增成功,type: success});this.dialogFormVisible false;this.resetForm()this.findBySearch(1);} else {this.$message.error(出错了,请联系管理员);}}).catch(error {console.error(请求失败, error);this.$message.error(网络错误请稍后再试);}).finally(() {this.isSubmitting false;});},handleSizeChange(val) {this.params.pageSize valthis.findBySearch()},handleCurrentChange(val) {this.params.pageNum valthis.findBySearch()}}, } /script 后端代码 持久层 关于#号 和历史模式有关 加上使用历史模式  mode:history就不会出现了 登录页面 路由级别 以上所有操作都在大布局下  路由也在同一级别 要想将登录页独立的一个页面 那么要将路由分级 首先个Layout.vue用来存放 原来app.vue路由 templatedivel-containerel-header stylebackground-color:blanchedalmond; display: flex; align-items: center; padding-left: 0px;img src/assets/logo.jpg alt stylewidth:250px; margin-left: 0px;/el-header/el-containerel-containerel-aside styleoverflow:hidden;min-height: 100vh;background-color:blanchedalmond;width: 250px;!-- default-active1默认是哪个 background-colorblanchedalmond 背景颜色 text-colorbrown 字体颜色 active-text-colorblue 选中字体颜色 --el-menu :default-active$route.path router background-colorblanchedalmond text-colorbrownactive-text-colorblueel-menu-item index/i classel-icon-menu/ispan slottitle系统首页/span/el-menu-itemel-submenu index2template slottitlei classel-icon-location/ispan用户管理/span/templateel-menu-item-groupel-menu-item index/admin管理员信息/el-menu-itemel-menu-item index2-2用户信息/el-menu-item/el-menu-item-group/el-submenuel-submenu index3template slottitlei classel-icon-location/ispan信息管理/span/templateel-menu-item-groupel-menu-item index3-1xxxx信息/el-menu-itemel-menu-item index3-2yyyy信息/el-menu-item/el-menu-item-group/el-submenu/el-menu/el-asideel-main!-- 我是入口 --router-view //el-main/el-container/div /templatescript export default {name: Layout} /scriptstyle .el-menu{border-right: none !important; } /style 将app.vue即程序入口还原成原来样子 templatediv idapprouter-view//div /templatestyle/style 代码结构 修改路由 router下的index.js文件 import Vue from vue import VueRouter from vue-router import HomeView from ../views/HomeView.vue import LoginView from ../views/LoginView.vue Vue.use(VueRouter)const routes [{path: /login,name: login,component: LoginView},{path: /,name: Layout,component: () import(../views/Layout.vue),children:[{path: /,name: home,component: HomeView},{path: /about,name: about,//懒加载component: () import(../views/AboutView.vue)},{path: /message,name: message,//懒加载component: () import(../views/MessageView.vue)},{path: /admin,name: admin,//懒加载component: () import(../views/AdminView.vue)}]}, ]const router new VueRouter({mode: history,routes })export default router编写登录页面 loginView.vue 访问http://localhost:8081/login 全局异常处理 全局异常处理ControllerAdvice可以指定包名或者类名 package com.example.backend.exception;import com.example.backend.common.Result; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody;import javax.servlet.http.HttpServletRequest;/*** author hrui* date 2024/3/14 11:26*/ ControllerAdvice Slf4j public class GlobalExceptionHandler {ExceptionHandler(Exception.class)ResponseBodypublic Result error(HttpServletRequest request,Exception e){log.error(异常信息:, e);return Result.error(系统异常, null);}ExceptionHandler(CustomException.class)ResponseBodypublic Result customError(HttpServletRequest request,CustomException e){log.error(CustomException异常信息:, e.getMessage());return Result.error(e.getMessage(), null);}}注册页面 templatediv classcontainerdiv classregister-boxform submit.preventonRegister classregister-formh2注册/h2div classform-groupinput v-modelregisterForm.name typetext placeholder用户名 blurcheckUsernameAvailabilityrequiredspan v-ifusernameAvailable stylecolor: red;{{ usernameErrorMessage }}/span/divdiv classform-groupinput v-modelregisterForm.password typepassword placeholder密码 required/divdiv classform-groupinput v-modelregisterForm.phone typetext placeholder手机号 required/divdiv classform-group action!-- button typebutton clicktriggerSlideVerification获取短信验证码/button --button clicktriggerSlideVerification :disabledisSMSButtonDisabled{{ smsButtonText }}/button/divdiv classform-group actionbutton typesubmit注册/button/divdiv classform-group actionbutton typebutton clickgoToLogin已有账号登录/button/div/form/div/div /templatescript import request from /api/HttpRequestexport default {name: RegisterView,data() {return {registerForm: {name: ,password: ,phone: },usernameAvailable: false,//用户名是否可用标识usernameErrorMessage: ,//不可用显示// 添加滑动验证的可见性状态isSlideVerificationVisible: false, // 控制滑动验证窗口的显示isSMSButtonDisabled: false, // 控制获取短信验证码按钮的可用状态countdown: 0,smsButtonText: 获取短信验证码,};},methods: {triggerSlideVerification() {// 显示滑动验证这里仅为示例具体实现取决于所用的滑动验证库this.isSlideVerificationVisible true;request.get(/api/checkimg).then(res{if(res.code200){console.log(data,res.data)}})// 假设滑动验证通过后调用 getSMSCode 方法this.getSMSCode();//this.startCountdown(); // 假设滑动验证通过},getSMSCode() {// 在这里调用获取短信验证码的APIconsole.log(滑动验证通过现在获取短信验证码);// 假设滑动验证通过隐藏滑动验证弹窗this.slideVerifyVisible false;},startCountdown() {if (this.countdown 0) return; // 防止重复点击this.isSMSButtonDisabled true; // 禁用获取短信验证码的按钮this.countdown 60;let intervalId setInterval(() {this.countdown--;this.smsButtonText ${this.countdown}秒后可重发;if (this.countdown 0) {clearInterval(intervalId);this.smsButtonText 获取短信验证码;this.isSMSButtonDisabled false; // 启用按钮this.isSlideVerificationVisible false; // 隐藏滑动验证窗口}}, 1000);},onRegister() {// 首先检查用户名是否可用if (!this.usernameAvailable) {this.$message.error(用户名不可用请更换用户名);return;}// 发送POST请求到后端的注册APIrequest.post(/api/register, this.registerForm).then(response {// 处理注册成功的情况if (response.code 200) {this.$message.success(注册成功);// 注册成功后可以选择跳转到登录页面或其他页面this.$router.push(/login);} else {// 后端返回了错误状态显示错误信息this.$message.error(response.msg || 注册失败);}}).catch(error {console.error(注册请求失败, error);this.$message.error(注册请求失败请稍后再试);});},checkUsernameAvailability() {//alert(111)if (this.registerForm.name.trim() ) {this.usernameAvailable true;this.usernameErrorMessage 用户名不能为空;return;}request.get(/api/usernamecheck, {params: {name: this.registerForm.name}}).then(response {if (response.code 200) {this.usernameAvailable false;this.usernameErrorMessage ;} else {this.usernameAvailable true;this.usernameErrorMessage response.msg;}}).catch(error {console.error(请求错误, error);this.$message.error(验证用户名时发生错误);});},goToLogin() {// 跳转到登录页面this.$router.push(/login);}}, }; /scriptstyle scoped .container {display: flex;justify-content: center;align-items: center;height: 100vh; }.register-box {width: 100%;max-width: 400px;padding: 20px;border: 1px solid #ccc;border-radius: 5px;box-shadow: 0 2px 4px rgba(0, 0, 0, .1); }.register-form {display: flex;flex-direction: column; }.form-group {margin-bottom: 20px; }input[typetext], input[typepassword] {width: 100%;padding: 10px;border: 1px solid #ccc;border-radius: 4px; }.action {display: flex;justify-content: center; }button[typesubmit], button[typebutton] {cursor: pointer;padding: 10px 20px;margin-right: 10px;background-color: #007bff;border: none;border-radius: 4px;color: white; }h2 {text-align: center;margin-bottom: 20px; } /style 用户登录之后到home页面 右上角退出功能 路由守卫 以上的页面  其实任何页面都可以进去 路由守卫就是对路由跳转进行身份验证(权限控制) 就是说你的地址符合我定义的规则 就允许访问 在路由配置文件里配置路由守卫 但是这种方式很不安全  因为用户可以自己设置 JWT  Token验证 就是因为上面路由守卫不安全   还是需要后端验证 大概思路是用户在登录页面登录之后  服务端会返回一个Token 客户端每次请求需要在请求头携带该Token,后端验证 通过就是可以访问,不通过返回登录页 给所有接口加上统一的调用前缀/api然后统一拦截该前缀的的请求 这样在前端的baseUrl中也需要添加 配置WebMvcConfigurer JWT工具类 package com.example.backend.common;import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.StrUtil; import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import com.example.backend.pojo.User; import com.example.backend.service.UserService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes;import javax.annotation.PostConstruct; import javax.servlet.http.HttpServletRequest; import java.util.Date;/*** author hrui* date 2024/3/15 0:54*/ Component Slf4j public class JwtTokenUtils {//主要是为了静态方法中使用Spring管理的bean 赋值后可以在静态方法这种使用 用起来方便 private static UserService staticUserService;Autowiredprivate UserService userService;PostConstructpublic void setUserService(){staticUserServiceuserService;}/*** 生成Token*/public static String genToken(String userId,String sign){return JWT.create().withAudience(userId)//将用户id保存到token做为荷载.withExpiresAt(DateUtil.offsetMinute(new Date(), 15))//15分钟过期.sign(Algorithm.HMAC256(sign));//以password做为Token密钥}/*** 获取当前登录用户信息*//*** 获取当前登录的用户信息*/public static User getCurrentUser() {String token null;try {HttpServletRequest request ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();token request.getHeader(token);if (StrUtil.isBlank(token)) {token request.getParameter(token);}if (StrUtil.isBlank(token)) {log.error(获取头部token为空token: {}, token);return null;}// 解析token获取用户的idString userId JWT.decode(token).getAudience().get(0);return staticUserService.findById(Integer.valueOf(userId));} catch (Exception e) {log.error(获取当前登录的用户信息失败, token{}, token, e);return null;}}}将token放到user中 前端处理 那么每次请求过来在拦截器进行校验 文件上传和下载 CREATE TABLE t_book (   id int NOT NULL AUTO_INCREMENT COMMENT 主键,   name varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 书名,   price varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 价格,   author varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 作者,   press varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 出版社,   image varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 封面,   PRIMARY KEY (id) ) ENGINEInnoDB AUTO_INCREMENT13 DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_unicode_ci; 前端代码 template!-- 需要有一个根div --divdiv stylemargin-bottom: 20px;el-input stylewidth: 300px; v-modelparams.name placeholder请输入书名/el-inputel-input stylewidth: 300px; margin-left: 20px; v-modelparams.press placeholder请输入出版社/el-inputel-button stylemargin-left: 20px; clickfindBySearch(1)查询/el-buttonel-button stylemargin-left: 20px; clickreset清空/el-buttonbrel-button typeprimary stylemargin-top: 20px; clickaddForm新增/el-buttonhr //divdivel-table :datatableData stylewidth: 100%el-table-column propname label书名 width180/el-table-columnel-table-column propprice label价格 width180/el-table-columnel-table-column propauthor label作者/el-table-columnel-table-column proppress label出版社/el-table-columnel-table-column label图片封面template slot-scopescopeel-image stylewidth: 100px; height: 100px;border-radius: 50%; :srchttp://localhost:8085/api/file/ scope.row.image :preview-src-list[http://localhost:8085/api/file/ scope.row.image]/el-image/template/el-table-columnel-table-column label操作template slot-scopescopeel-button typeprimary clickedit(scope.row)编辑/el-buttonel-popconfirm title确定要删除这条记录吗 confirmdeleteRow(scope.row.id) confirm-button-text确定cancel-button-text取消template #referenceel-button typedanger stylemargin-left: 10px;删除/el-button/template/el-popconfirm/template/el-table-column/el-table/divdivel-pagination stylemargin-top: 20px; size-changehandleSizeChangecurrent-changehandleCurrentChange :current-pageparams.pageNum :page-sizes[5, 10, 15, 20]:page-sizeparams.pageSize layouttotal, sizes, prev, pager, next, jumper :totaltotalNum/el-pagination/divdivel-dialog :titledialogTitle :visible.syncdialogFormVisible closeresetFormel-form :modelformel-form-item label书名 :label-widthformLabelWidthel-input v-modelform.name autocompleteoff/el-input/el-form-itemel-form-item label价格 :label-widthformLabelWidthel-input v-modelform.price autocompleteoff/el-input/el-form-itemel-form-item label作者 :label-widthformLabelWidthel-input v-modelform.author autocompleteoff/el-input/el-form-itemel-form-item label出版社 :label-widthformLabelWidthel-input v-modelform.press autocompleteoff/el-input/el-form-itemel-form-item label图书封面 :label-widthformLabelWidth!-- :headersuploadHeaders 可以动态加上请求头token 或者 后端放行 --el-upload classupload-demo actionhttp://localhost:8085/api/file/upload:headersuploadHeaders :on-errorerrorUpload :on-successsuccessUploadel-button sizesmall typeprimary点击上传/el-button/el-upload/el-form-item/el-formdiv slotfooter classdialog-footerel-button clickdialogFormVisible false取 消/el-buttonel-button typeprimary clicksubmit :disabledisSubmitting确 定/el-button/div/el-dialog/div/div /template script import request from /api/HttpRequest export default {name: BookView,data() {return {dialogFormVisible: false,isEdit: false, // 标志是编辑状态还是新增状态dialogTitle: , // 对话框标题params: {name: ,press: ,pageNum: 1,pageSize: 5,},uploadHeaders: {token: sessionStorage.getItem(token)},totalNum: 0,tableData: [],form: {},formLabelWidth: 120px,isSubmitting: false //提交标志}},created() {this.findBySearch()},methods: {//文件上传成功后的钩子 successUpload(res) {//console.log(res)if (res.code 200) {this.form.image res.data}},errorUpload(res) {console(res)},resetForm() {this.form {name: ,price: ,author: ,press: ,image: };},reset() {this.params.name this.params.press this.findBySearch()},findBySearch(val) {if (val 1) {this.params.pageNum 1this.params.pageSize 5}request.get(/book/findBooks, {params: this.params}).then(res {if (res.code 200) {this.tableData res.data.listthis.totalNum res.data.total} else {}})},addForm() {this.resetForm(); // 重置表单this.isEdit false; // 设置为新增模式this.dialogTitle 新增管理员信息; // 设置对话框标题this.dialogFormVisible true; // 显示对话框},edit(row) {this.isEdit true; // 设置为编辑模式this.dialogTitle 更新管理员信息; // 设置对话框标题this.form Object.assign({}, row); // 深拷贝行数据到表单//this.formrowthis.dialogFormVisible true; // 显示对话框},deleteRow(id) {// 这里应该调用API来删除row代表的数据// 例如this.isSubmitting true;request.delete(/book/deleteBook/${id}).then(res {if (res.code 200) {this.$message.success(删除成功);this.findBySearch(); // 重新加载当前页的数据或者根据需要更新视图} else {this.$message.error(删除失败请稍后再试);}}).catch(error {this.$message.error(网络错误请稍后再试);}).finally(() {this.isSubmitting false;});},submit() {if (this.isSubmitting) return;this.isSubmitting true;const api this.isEdit ? /book/save : /book/save;request.post(api, this.form).then(res {if (res.code 200) {this.$message({message: this.isEdit ? 更新成功 : 新增成功,type: success});this.dialogFormVisible false;this.resetForm()this.findBySearch(1);} else {this.$message.error(出错了,请联系管理员);}}).catch(error {this.$message.error(网络错误请稍后再试);}).finally(() {this.isSubmitting false;});},handleSizeChange(val) {this.params.pageSize valthis.findBySearch()},handleCurrentChange(val) {this.params.pageNum valthis.findBySearch()}}, } /script 后端代码 控制器 package com.example.backend.controller;import com.example.backend.common.Result; import com.example.backend.pojo.Book; import com.example.backend.service.BookService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;/*** author hrui* date 2024/3/15 23:24*/ RestController RequestMapping(/book) public class BookController {Autowiredprivate BookService bookService;RequestMapping(/save)public Result saveBook(RequestBody Book book){ // if(book.getId()null){ // int i bookService.insertBook(book); // if(i0){ // return Result.success(新增成功, null); // }else{ // return Result.error(新增失败, null); // } // }else{ // int ibookService.updateBook(book); // if(i0){ // return Result.success(更新成功, null); // }else{ // return Result.error(更新失败, null); // } // }boolean success book.getId() null ? bookService.insertBook(book) 0 : bookService.updateBook(book) 0;return success ? Result.success(操作成功, null) : Result.error(操作失败, null);}RequestMapping(/findBooks)public Result findBooks(Book book){return Result.success(查询成功, bookService.findBooks(book));}RequestMapping(/deleteBook/{id})public Result deleteBookById(PathVariable Integer id){return bookService.deleteBookById(id)0?Result.success(删除成功, null):Result.error(删除失败, null);} }业务层 package com.example.backend.service.impl;import com.example.backend.mapper.BookMapper; import com.example.backend.pojo.Book; import com.example.backend.pojo.User; import com.example.backend.service.BookService; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service;import java.util.List;/*** author hrui* date 2024/3/15 23:25*/ Service public class BookServiceImpl implements BookService {Autowiredprivate BookMapper bookMapper;Overridepublic int insertBook(Book book) {return bookMapper.insertBook(book);}Overridepublic int updateBook(Book book) {return bookMapper.updateBook(book);}Overridepublic PageInfoBook findBooks(Book book) {PageObject objects PageHelper.startPage(book.getPageNum(), book.getPageSize());return new PageInfo(bookMapper.selectBookByCondition(book));}Overridepublic int deleteBookById(Integer id) {return bookMapper.deleteBookById(id);} }持久层 package com.example.backend.mapper;import com.example.backend.pojo.Book; import com.example.backend.pojo.User; import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update;import java.util.List;/*** author hrui* date 2024/3/15 23:24*/ public interface BookMapper {Insert({script,insert into t_book,trim prefix( suffix) suffixOverrides,,id,,if testname!null and name!\\,name,,/if,if testprice!null and price!\\,price,,/if,if testauthor!null and author!\\,author,,/if,if testpress!null and press!\\,press,,/if,if testimage!null and image!\\,image,,/if,/trim,values,trim prefix( suffix) suffixOverrides,,null,,if testname!null and name!\\,#{name},,/if,if testprice!null and price!\\,#{price},,/if,if testauthor!null and author!\\,#{author},,/if,if testpress!null and press!\\,#{press},,/if,if testimage!null and image!\\,#{image},,/if,/trim,/script})int insertBook(Book book);Update({script,UPDATE t_book,set,if testname!null and name!\\,name #{name},,/if,if testprice!null and price!\\,price #{price},,/if,if testauthor!null and author!\\,author #{author},,/if,if testpress!null and press!\\,press #{press},,/if,if testimage!null and image!\\,image #{image},,/if,/set,WHERE id #{id},/script})int updateBook(Book book);// Select(select * from t_book) // ListBook selectAllBooks();Select({script select * from t_book whereif testname!null and name!\\ // and name#{name}and name like concat(%,#{name},%)/ifif testprice!null and price!\\ and price#{price}/ifif testauthor!null and author!\\ and author#{author}/ifif testpress!null and press!\\ // and press#{press}and press like concat(%,#{press},%)/if/where/script})ListBook selectBookByCondition(Book book);Delete(DELETE FROM t_book WHERE id #{id})int deleteBookById(Integer id); }文件上传 控制器 package com.example.backend.controller;import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.StrUtil; import com.example.backend.common.Result; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletResponse; import java.io.OutputStream; import java.net.URLEncoder; import java.util.List;/*** author hrui* date 2024/3/16 1:47*/ RestController RequestMapping(/file) Slf4j public class FileController {//文件上传存储路径private static final String filePathSystem.getProperty(user.dir)/upload/;/*** 文件上传*/PostMapping(/upload)public Result upload(MultipartFile file) {synchronized (FileController.class) {//加锁 确保文件名不重复String flag System.currentTimeMillis() ;//原始文件名String fileName file.getOriginalFilename();try {if (!FileUtil.isDirectory(filePath)) {FileUtil.mkdir(filePath);}// 文件存储位置原逻辑-文件名FileUtil.writeBytes(file.getBytes(), filePath flag - fileName);System.out.println(fileName --上传成功);//Thread.sleep(1L);} catch (Exception e) {System.err.println(fileName --文件上传失败);}return Result.success(上传成功,flag);}}/*** 文件下载*/// GetMapping映射HTTP GET请求到特定的处理方法 // PathVariable用来接收请求URL中的flag值GetMapping(/{flag})public void avatarPath(PathVariable String flag, HttpServletResponse response) {// 检查filePath是否是目录如果不是则创建if (!FileUtil.isDirectory(filePath)) {FileUtil.mkdir(filePath);}// 用于写入响应流的输出流OutputStream os;// 获取filePath路径下的所有文件名ListString fileNames FileUtil.listFileNames(filePath);// 从文件名列表中筛选包含flag的文件名如果没有找到则返回空字符串String avatar fileNames.stream().filter(name - name.contains(flag)).findAny().orElse();try {// 如果avatar不为空则执行文件下载操作if (StrUtil.isNotEmpty(avatar)) {// 设置响应的头部信息告诉浏览器这是一个附件下载操作并提供文件名response.addHeader(Content-Disposition, attachment;filename URLEncoder.encode(avatar, UTF-8));// 设置响应的内容类型为字节流response.setContentType(application/octet-stream);// 读取filePath和avatar组合后的文件路径的所有字节byte[] bytes FileUtil.readBytes(filePath avatar);// 获取响应的输出流os response.getOutputStream();// 写入字节到响应输出流os.write(bytes);// 刷新输出流os.flush();// 关闭输出流os.close();}} catch (Exception e) {// 如果文件传输失败打印失败信息System.out.println(文件传输失败);}}public static void main(String[] args) {ListString fileNames FileUtil.listFileNames(filePath);}}拦截器放行 实现批量删除 这里存在一个问题 实现Excel导入导出 版本不低于4.1.2 后端 package com.example.backend.controller;import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.io.IoUtil; import cn.hutool.poi.excel.ExcelUtil; import cn.hutool.poi.excel.ExcelWriter; import com.example.backend.common.Result; import com.example.backend.exception.ExcelEmptyException; import com.example.backend.pojo.BookType; import com.example.backend.service.BookTypeService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile;import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map;/*** author hrui* date 2024/3/16 11:04*/ RestController RequestMapping(/excel) public class ExcelController {Autowiredprivate BookTypeService bookTypeService;RequestMapping(/bookTypeExcelExport)public void booTypeExcelExport(HttpServletResponse response) throws IOException {// 1. 从数据库中查询出所有数据ListBookType listbookTypeService.selectAllBookType();if(CollectionUtil.isEmpty(list)){throw new ExcelEmptyException(图书分类中没有数据);}// 2. 定义一个 List 和 Mapkey,value 出来存储处理之后的数据用于导出 list 集// 3. 遍历每一条数据然后封装到 Mapkey,value key是列名 value是值 里把这个 map 集到 list 集ListMapString,Object list2new ArrayList();for(BookType bt:list){MapString,Object rownew HashMap();row.put(图书名称, bt.getName());row.put(图书描述,bt.getDescription());list2.add(row);}// 4. 创建一个 ExcelWriter,把 list 集合放入到writer写出生成数据ExcelWriter writer ExcelUtil.getWriter(true);writer.write(list,true);// 5. 把这个 excel 下载下来response.setContentType(application/vnd.openxmlformats-officedocument.spreadsheetml.sheet);response.setHeader(Content-Disposition, attachment;filenamebookType.xlsx);ServletOutputStream out response.getOutputStream();writer.flush(out, true);writer.close();IoUtil.close(System.out);};PostMapping(/upload)public Result excelUpload(MultipartFile file) throws IOException {ListBookType types ExcelUtil.getReader(file.getInputStream()).readAll(BookType.class);if(!CollectionUtil.isEmpty(types)){for(BookType t:types){try{bookTypeService.insertBookType(t);}catch (Exception e){e.printStackTrace();}}}return Result.success(导入成功, null);} }前端 template!-- 需要有一个根div --divdiv stylemargin-bottom: 20px;el-input stylewidth: 300px; v-modelparams.name placeholder请输入名称/el-inputel-input stylewidth: 300px; margin-left: 20px; v-modelparams.descriptionplaceholder请输入描述/el-inputel-button stylemargin-left: 20px; clickfindBySearch(1)查询/el-buttonel-button stylemargin-left: 20px; clickreset清空/el-buttonbrel-button typeprimary stylemargin-top: 20px; clickaddForm新增/el-buttonel-popconfirm title确定要删除这些记录吗 confirmdeleteBatch confirm-button-text确定 cancel-button-text取消template #referenceel-button typedanger stylemargin-left: 10px;批量删除/el-button/template/el-popconfirmel-button typesuccess stylemargin-left: 10px; clickexcelExportExcel导出/el-buttonel-upload styledisplay: inline-block;margin-left: 10px; actionhttp://localhost:8085/api/excel/upload :headersuploadHeaders :on-successsuccessUpload :show-file-listfalseel-button typesuccessExcel导入/el-button/el-uploadhr //divdivel-table :datatableData stylewidth: 100% selection-changehandleSelectionChange row-keyidreftableel-table-column typeselection reftable :reserve-selectiontrue width55/el-table-columnel-table-column propname label分类名称 width180/el-table-columnel-table-column propdescription label分类描述/el-table-columnel-table-column label操作template slot-scopescopeel-button typeprimary clickedit(scope.row)编辑/el-buttonel-popconfirm title确定要删除这条记录吗 confirmdeleteRow(scope.row.id) confirm-button-text确定cancel-button-text取消template #referenceel-button typedanger stylemargin-left: 10px;删除/el-button/template/el-popconfirm/template/el-table-column/el-table/divdivel-pagination stylemargin-top: 20px; size-changehandleSizeChangecurrent-changehandleCurrentChange :current-pageparams.pageNum :page-sizes[5, 10, 15, 20]:page-sizeparams.pageSize layouttotal, sizes, prev, pager, next, jumper :totaltotalNum/el-pagination/divdivel-dialog :titledialogTitle :visible.syncdialogFormVisible closeresetFormel-form :modelformel-form-item label分类名称 :label-widthformLabelWidthel-input v-modelform.name autocompleteoff/el-input/el-form-itemel-form-item label分类描述 :label-widthformLabelWidthel-input v-modelform.description autocompleteoff/el-input/el-form-item/el-formdiv slotfooter classdialog-footerel-button clickdialogFormVisible false取 消/el-buttonel-button typeprimary clicksubmit :disabledisSubmitting确 定/el-button/div/el-dialog/div/div /template script import request from /api/HttpRequest export default {name: BookTypeView,data() {return {uploadHeaders: {token: sessionStorage.getItem(token)},dialogFormVisible: false,isEdit: false, // 标志是编辑状态还是新增状态dialogTitle: , // 对话框标题params: {name: ,description: ,pageNum: 1,pageSize: 5,},totalNum: 0,tableData: [],form: {},formLabelWidth: 120px,isSubmitting: false, //提交标志multipleSelection: []}},created() {this.findBySearch()},methods: {handleExceed(files, fileList) {this.$message.warning(只能上传一张图片);},//文件上传成功后的钩子 successUpload(res) {//console.log(res)if (res.code 200) {this.$message.success(res.msg)this.findBySearch()}else{this.$message.error(res.msg)}},excelExport() {location.hrefhttp://localhost:8085/api/excel/bookTypeExcelExport?tokensessionStorage.getItem(token) },handleSelectionChange(val) {//val本身是个数组 使用 map 函数遍历 val 数组提取每行数据的 id并保存到 multipleSelection 数组中this.multipleSelection val.map(item item.id);console.log(JSON.stringify(this.multipleSelection))},deleteBatch() {//判断multipleSelection是否为空if (this.multipleSelection.length 0) {this.$message.warning(请勾选要删除的数据)return}request.put(/bookType/deleteBatch, this.multipleSelection).then(res {if (res.code 200) {this.$message.success(批量删除成功)this.findBySearch()} else {this.$message.success(res.msg)}}).catch(error {this.$message.error(网络错误请稍后再试);}).finally(() {});},resetForm() {this.form {name: ,description: ,};},reset() {this.params.name this.params.description this.findBySearch()},findBySearch(val) {if (val 1) {this.params.pageNum 1this.params.pageSize 5}request.get(/bookType/findBookType, {params: this.params}).then(res {if (res.code 200) {this.tableData res.data.listthis.totalNum res.data.total} else {}})},addForm() {this.resetForm(); // 重置表单this.isEdit false; // 设置为新增模式this.dialogTitle 新增管理员信息; // 设置对话框标题this.dialogFormVisible true; // 显示对话框},edit(row) {this.isEdit true; // 设置为编辑模式this.dialogTitle 更新管理员信息; // 设置对话框标题this.form Object.assign({}, row); // 深拷贝行数据到表单//this.formrowthis.dialogFormVisible true; // 显示对话框},// deleteRow(id) {// // 这里应该调用API来删除row代表的数据// // 例如// this.isSubmitting true;// request.delete(/bookType/deleteBookType/${id}).then(res {// if (res.code 200) {// this.$message.success(删除成功);// this.findBySearch(); // 重新加载当前页的数据或者根据需要更新视图// } else {// this.$message.error(删除失败请稍后再试);// }// }).catch(error {// this.$message.error(网络错误请稍后再试);// }).finally(() {// this.isSubmitting false;// });// },submit() {if (this.isSubmitting) return;this.isSubmitting true;const api this.isEdit ? /bookType/save : /bookType/save;request.post(api, this.form).then(res {if (res.code 200) {this.$message({message: this.isEdit ? 更新成功 : 新增成功,type: success});this.dialogFormVisible false;this.resetForm()this.findBySearch(1);} else {this.$message.error(出错了,请联系管理员);}}).catch(error {this.$message.error(网络错误请稍后再试);}).finally(() {this.isSubmitting false;});},handleSizeChange(val) {this.params.pageSize valthis.findBySearch()},handleCurrentChange(val) {this.params.pageNum valthis.findBySearch()}}, } /script 模块之间关联关系 将图书分类和图书信息做关联  一般不用外键  主要是添加外键存在强耦合关系 图书分类对应多个图书信息 1对多 在多的一方建个字段关联图书分类表 展示时候数据也可以从后端关联查询出来 template!-- 需要有一个根div --divdiv stylemargin-bottom: 20px;el-input stylewidth: 300px; v-modelparams.name placeholder请输入书名/el-inputel-input stylewidth: 300px; margin-left: 20px; v-modelparams.press placeholder请输入出版社/el-inputel-button stylemargin-left: 20px; clickfindBySearch(1)查询/el-buttonel-button stylemargin-left: 20px; clickreset清空/el-buttonbrel-button typeprimary stylemargin-top: 20px; clickaddForm新增/el-buttonhr //divdivel-table :datatableData stylewidth: 100%el-table-column propname label书名 width180/el-table-columnel-table-column propprice label价格 width180/el-table-columnel-table-column propauthor label作者/el-table-columnel-table-column proppress label出版社/el-table-columnel-table-column label图片封面template slot-scopescopeel-image stylewidth: 100px; height: 100px;border-radius: 50%;:srchttp://localhost:8085/api/file/ scope.row.image:preview-src-list[http://localhost:8085/api/file/ scope.row.image]/el-image/template/el-table-columnel-table-column label图书类别 width180template v-slot:defaultscope!-- 这里假设每行的数据中有 typeId 字段且options是所有类别的数组 --{{ findTypeName(scope.row.typeId) }}/template/el-table-columnel-table-column label操作template slot-scopescopeel-button typeprimary clickedit(scope.row)编辑/el-buttonel-button typeprimary clickdown(scope.row.image)下载/el-buttonel-popconfirm title确定要删除这条记录吗 confirmdeleteRow(scope.row.id) confirm-button-text确定cancel-button-text取消template #referenceel-button typedanger stylemargin-left: 10px;删除/el-button/template/el-popconfirm/template/el-table-column/el-table/divdivel-pagination stylemargin-top: 20px; size-changehandleSizeChangecurrent-changehandleCurrentChange :current-pageparams.pageNum :page-sizes[5, 10, 15, 20]:page-sizeparams.pageSize layouttotal, sizes, prev, pager, next, jumper :totaltotalNum/el-pagination/divdivel-dialog :titledialogTitle :visible.syncdialogFormVisible closeresetFormel-form :modelformel-form-item label书名 :label-widthformLabelWidthel-input v-modelform.name autocompleteoff/el-input/el-form-itemel-form-item label价格 :label-widthformLabelWidthel-input v-modelform.price autocompleteoff/el-input/el-form-itemel-form-item label作者 :label-widthformLabelWidthel-input v-modelform.author autocompleteoff/el-input/el-form-itemel-form-item label出版社 :label-widthformLabelWidthel-input v-modelform.press autocompleteoff/el-input/el-form-itemel-form-item label图书封面 :label-widthformLabelWidth!-- :headersuploadHeaders 可以动态加上请求头token 或者 后端放行 --el-upload classupload-demo actionhttp://localhost:8085/api/file/upload:headersuploadHeaders :on-errorerrorUpload :on-successsuccessUpload :limit1:on-exceedhandleExceedel-button sizesmall typeprimary点击上传/el-button/el-upload/el-form-itemel-form-item label图书类别 :label-widthformLabelWidthel-select v-modelform.typeId placeholder请选择图书类别el-option v-foritem in options :keyitem.id :labelitem.name :valueitem.id/el-option/el-select/el-form-item/el-formdiv slotfooter classdialog-footerel-button clickdialogFormVisible false取 消/el-buttonel-button typeprimary clicksubmit :disabledisSubmitting确 定/el-button/div/el-dialog/div/div /template script import request from /api/HttpRequest export default {name: BookView,data() {return {dialogFormVisible: false,isEdit: false, // 标志是编辑状态还是新增状态dialogTitle: , // 对话框标题params: {name: ,press: ,pageNum: 1,pageSize: 5,},uploadHeaders: {token: sessionStorage.getItem(token)},totalNum: 0,tableData: [],form: {},formLabelWidth: 120px,isSubmitting: false, //提交标志options: []}},created() {this.findBySearch()this.selectOptions()},methods: {findTypeName(typeId) {const type this.options.find(option option.id typeId);return type ? type.name : ;},selectOptions() {request.get(/bookType/findBookTypes).then(res {if (res.code 200) {this.options res.data//console.log(res.data)}})},down(imageName) {location.href http://localhost:8085/api/file/ imageName},handleExceed(files, fileList) {this.$message.warning(只能上传一张图片);},//文件上传成功后的钩子 successUpload(res) {//console.log(res)if (res.code 200) {this.form.image res.data}},errorUpload(res) {console(res)},resetForm() {this.form {name: ,price: ,author: ,press: ,image: ,typeId: };},reset() {this.params.name this.params.press this.findBySearch()},findBySearch(val) {if (val 1) {this.params.pageNum 1this.params.pageSize 5}request.get(/book/findBooks, {params: this.params}).then(res {if (res.code 200) {this.tableData res.data.listthis.totalNum res.data.total} else {}})},addForm() {this.resetForm(); // 重置表单this.isEdit false; // 设置为新增模式this.dialogTitle 新增管理员信息; // 设置对话框标题this.dialogFormVisible true; // 显示对话框},edit(row) {this.isEdit true; // 设置为编辑模式this.dialogTitle 更新管理员信息; // 设置对话框标题this.form Object.assign({}, row); // 深拷贝行数据到表单//this.formrowthis.dialogFormVisible true; // 显示对话框},deleteRow(id) {// 这里应该调用API来删除row代表的数据// 例如this.isSubmitting true;request.delete(/book/deleteBook/${id}).then(res {if (res.code 200) {this.$message.success(删除成功);this.findBySearch(); // 重新加载当前页的数据或者根据需要更新视图} else {this.$message.error(删除失败请稍后再试);}}).catch(error {this.$message.error(网络错误请稍后再试);}).finally(() {this.isSubmitting false;});},submit() {if (this.isSubmitting) return;this.isSubmitting true;const api this.isEdit ? /book/save : /book/save;request.post(api, this.form).then(res {if (res.code 200) {this.$message({message: this.isEdit ? 更新成功 : 新增成功,type: success});this.dialogFormVisible false;this.resetForm()this.findBySearch(1);} else {this.$message.error(出错了,请联系管理员);}}).catch(error {this.$message.error(网络错误请稍后再试);}).finally(() {this.isSubmitting false;});},handleSizeChange(val) {this.params.pageSize valthis.findBySearch()},handleCurrentChange(val) {this.params.pageNum valthis.findBySearch()}}, } /script 如果用关联表查询也可以 下面是通过id去查name 角色权限控制 例如某些页面的增删改查按钮  管理员角色可以操作   而普通用户只能浏览 某些页面管理员可以访问   但是可能普通用户不给予访问(看不到) 在用户表添加角色字段   这个字段用int  也可以 随自己 现在角色字段添加了  但是 登录admin或者张三 都是可以看到所有页面的 要做的是根据角色不同  所能看到的菜单不同 审核功能 请假申请  审核功能为例

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/89756.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

淘宝店铺网站策划wordpress网站专题

前言:常用的ORM框架有哪些 JdbcTemplate JdbcTemplate 是Spring框架提供的一个JDBC抽象库,旨在简化传统的JDBC操作,避免了繁琐的JDBC代码和数据库资源的手动处理。通过JdbcTemplate,开发者可以更加专注于业务逻辑而不是数据库的连…

做直播网站软件有哪些软件有哪些seo网站关键词优化报价

#undef 是在后面取消以前定义的宏定义 该指令的形式为 #undef 标识符 其中,标识符是一个宏名称。如果标识符当前没有被定义成一个宏名称,那么就会忽略该指令。一旦定义预处理器标识符,它将保持已定义状态且在作用域内,直到程序结束…

母婴网站建设初衷2018做网站 工具

观察者模式监听判断dom元素是否在可视区域内 本项目是使用vue3的写法。 1.IntersectionObserver IntersectionObserver可以用来自动监听元素是否进入了设备的可视区域之内,而不需要频繁的计算来做这个判断。由于可见(visible)的本质是&…

蔡家坡网站开发html网页制作步骤

给定不超过6的正整数A,考虑从A开始的连续4个数字。请输出所有由它们组成的无重复数字的3位数。 输入格式: 输入在一行中给出A。 输出格式: 输出满足条件的的3位数,要求从小到大,每行6个整数。整数间以空格分隔&#…

有没有做catalog的网站大连网站建设找哪家好

题目 幼儿园里有 N 个小朋友,老师现在想要给这些小朋友们分配糖果,要求每个小朋友都要分到糖果。 但是小朋友们也有嫉妒心,总是会提出一些要求,比如小明不希望小红分到的糖果比他的多,于是在分配糖果的时候&#xff…

服务器对应的网站开发语言太姥山镇建设的网站

思维导图:https://www.processon.com/view/link/5f0a6983e401fd0c8fffa75b

做网站要懂哪些杭州工程网站建设

前言大家应该都知道,整数包括负数,零,和正数。在Java中,基本类型中byte(8位)、short(16位)、int(32位)、long(64位)属于整数,并且没有无符号数,均是有符号的。对于计算机来说,它只认识二进制&am…

什么网站的地图厦门 网站优化

本节课主要是跟着教程做的,操作的东西放到作业里记录了。 这里主要记录一些视频里讲的非操作性的东西。 RAG外挂知识库?优点是成本低,不用重新训练 RAG的一个整体流程。 涉及了文本相似度匹配,是不是和传统的问答系统&#xff0…

石家庄网站建设外包保定网站推广哪家好

IoC按名称查找共分为三类: 按名称按类型按集合 按名称查找 在Spring Framework中,实时加载和延迟加载是指在容器启动时是否立即实例化bean的不同策略。下面我们将分别介绍这两种加载方式及其应用场景。 tips: 当涉及到懒加载和延时加载时&#xff0…

佛山营销网站建设制作石家庄优化seo

Maven环境搭建及配置 1.下载部署 官方网站下载正式版的Maven文件,打开bin目录,复制路径然后去环境变量中的path下配置环境变量, 如果只有一个用户只需要在上面path配置复制的路径,当然也可以直接在下面配置,下面配置默认给所有用户都配置 设置完成打开控…

dede手机医院网站模板下载辽宁省建设注册中心网站

问答系统需求文档 一、项目概述 本项目旨在开发一个能够上传 PDF 文件,并基于 PDF 内容进行问答互动的系统。用户可以上传 PDF 文件,系统将解析 PDF 内容,并允许用户通过对话框进行问答互动,获取有关 PDF 文件内容的信息。 二、…

可商用的设计网站网页设计网站总结报告怎么写

在一些应用领域,电源模块会在极端环境温度条件下工作。为了确保电源在高低温环境下可以正常运行,满足设备需求,需要对电源模块进行温度循环测试。 温度循环测试是指电源模块经过升温、保温、降温等多次循环试验来检测其在温度变化下的耐热性、…

广州网站制作方法公司做网站怎么做

如何判断exe文件是debug还是release编译生成的结论: 用IDA工具打开exe,然后看Imports里面的依赖库是否有带d或D结尾的,如果有就说明是Debug的 实验:(实验环境 vs2017, IDA工具) (0&…

怎么做网站推广临沂网站建设的基本流程包括什么

很多个人站长和中小企业在做网站的时候,会选择虚拟主机。虚拟主机用的操作系统多为Windows系统,很多人一提到操作系统立马联想到Windows系统。其实除了Windows系统外,还有很多的操作系统。其中Linux系统是其中的佼佼者。 1、操作系统 window…

泰安润泽建设工程有限公司网站做购物网站怎么赚钱

一直都是编译armabi的。没有不论什么问题,这个架构是软件模拟浮点运算的。后来看到NDK文档上说armabi-v7a是针对有硬件处理浮点计算的arm cpu的。 于是就改动配置编译armebai-v7a的so文件。 结果是编译没问题。一执行就是crash掉,Fatal signal 7 (SIGSEG…

做摄影哪个网站12306网站建设投标书

目录 第一章、代码①trim() 方法以及(Arrays.asList(str.split(reg)));②查询字典项 第二章、注解①PropertySource("classpath:coremail.properties") 第三章、小知识①Linux系统中使用$符号表示变量 友情提醒: 先看文章目录,大致了解文章知识点结构&am…

淘宝上的网站建设为什么便宜天猫网站是用什么技术做的

实验需求 拓扑 实验注意点: 先配置双机热备,再来配置安全策略和NAT两台双机热备的防火墙的接口号必须一致如果其中一台防火墙有过配置,最好清空或重启,不然配置会同步失败两台防火墙同步完成后,可以直接在主状态防火墙…

深圳做响应式网站制作上海网站推广网络公司

在进行linux测试时编写脚本是必不可少的。最近经常使用Linux,感觉太频繁地敲击键盘有些累了,于是想到了Shell脚本。可以把太多的命令写成一个脚本,这样每次执行一遍 shell文件,就可以省去了敲击键盘的时间。于是在网上搜了一些有…

杭州建设网站设计的公司北京故宫网页设计

<style type"text/css">font-face{font-family:myFont;src:url(/bootstrap-3.3.7-dist/fonts/shishangjianti.ttf);}body{font-family: myFont !important;}</style> .ttf的文件路径根据文件位置定义

如何制作手机版网站厦门网络推广建网站

电脑网页的设计尺寸是多少刚入门的网页设计师可能对电脑网页的设计尺寸大小存在疑问&#xff0c;以下百分网小编整理的电脑网页的设计尺寸&#xff0c;希欢迎阅读!  对大于30W台客户端用户进行测试&#xff0c;得到的测试数据如下(数据来源于网络)&#xff1a;安全分辨率为10…