Springboot+Vue实现简单的前端后分离数据交互

23 篇文章 5 订阅
订阅专栏
4 篇文章 0 订阅
订阅专栏

目录

一,前后端分离介绍

二,与传统单体结构的比较

2.1,传统单体结构开发

2.2,前后端分离结构开发

三,简单实现前后端数据交互

1,准备的环境及工具

2,开发步骤

2.1,后端部分

2.2,前端部分

2.3,项目运行及实现结果

​编辑

四,简单总结 


一,前后端分离介绍

所谓的前后端分离,就是将一个应用开发的前后端编码分开来写。后端负责处理,存储数据,而前端,则主要通过后端提供的数据接口,对数据进行渲染展示。通过这样前后端分工合作,使得项目的分工更加明确,大大降低了前后端代码的之间的耦合度,提高了开发效率。

二,与传统单体结构的比较

2.1,传统单体结构开发

传统的开发主要是,前端通过编写HTML静态界面,然后通过将界面内嵌到JSP中,或者使用Thymeleaf模板解析HTML静态界面。后端通过MVC架构中的DispatcherServlet将处理请求中的数据渲染ModelAndView或者Model到指定的静态界面中,从而达到前后端的整合。

整体的结构如图所示:

在这样一体化的构造中,如果后端业务逻辑需要更改或者数据获取出现问题,前端就要跟后端协调沟通,或者业务功能更加复杂时,这样一体化的弊端就会愈发明显。耦合度高,开发麻烦,严重影响开发效率。

2.2,前后端分离结构开发

采用前后端分离的方式进行开发时,前端只需要独立去编写客户端代码,后端专心于编写服务端代码,然后提供数据接口即可。前端开发人员与后端人员通过约定好接口文档(URL,数据类型,参数)就可以分别进行独立开发,并且,前端还可以进行伪数据构造进行数据展示测试。不需要完全依赖于后端,最后集成一下就能实现相应的业务功能了,从而达到前后端的解耦,大大提高开发效率。

整体结构如图所示:

这样开发以后,前后端开发人员可以更专注于自己擅长的领域,实现职责分离。

  • 前后端仅仅通过异步接口(AJAX/JSONP)来编程
  • 前后端都各自有自己的开发流程,构建工具,测试集合
  • 关注点分离,前后端变得相对独立并解耦合
前端后端
接受,展示数据提供数据
处理渲染逻辑处理业务逻辑
MVVM架构MVC架构
专注于客户端代码构造专注于服务器代码构造

三,简单实现前后端数据交互

1,准备的环境及工具

开发准备前端后端
环境node.js jdk1.8,tomcat9,mysql8
技术集成vue,axios,element-plusSpringboot,MyBatis-plus
开发工具Visual Studio CodeIntelliJ IDEA 2022.1,Navicat Premium ,(ApiPost6)

2,开发步骤

2.1,后端部分

2.1.1,构造一个数据库,准备一张用于数据展示的数据表

create table test_user
(
    id         int(20) auto_increment comment '用户id'
        primary key,
    name       varchar(30) null comment '用户姓名',
    sex        tinyint(1)  null comment '性别(1为男,0为女)',
    address    varchar(45) null comment '用户地址',
    createTime datetime    null,
    constraint id_index
        unique (id) comment 'id为唯一索引'
);

构建存储过程快速插入100条数据,详情方法查看 如何使用存储过程快速插入数据

 2.1.2,在IDEA里创建一个SpringBoot项目,并导入相关依赖

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
<dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--        MP代码生成器依赖-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.5.1</version>
        </dependency>
        <!--        3.0版本的swagger依赖-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-boot-starter</artifactId>
            <version>3.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.83</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>2.2.5</version>
        </dependency>

2.1.3,配置yml文件里面的数据库配置

server:
  port: 8090
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    password: 123456
    username: root
    url: jdbc:mysql://localhost:3306/db_user?&useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
  mvc:
    format:
      date-time: yyyy-MM-dd HH:mm



mybatis-plus:
  mapper-locations: classPath*:/mapper/*.xml
  configuration:
    map-underscore-to-camel-case: false # 禁止大写变小写时自动添加下划线
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

2.1.4,通过MyBatis-plus代码生成器,直接构建基础的项目结构(pojo,service,dao,serviceImpl,controller),通过MyBatis-Plus自动生成代码后,我们基本的一些代码全部省去了,包括业务需要的简单增删改查也全部轻松自动搞定。需要注意的是,自动生成的代码并不能完全适用于我们所有业务,如果业务需求有变,还是需要我们自己手动编写动态SQL,不要过于依赖框架哦~~~~这样后端基本的框架就搭建成功了

2.1.5, 考虑到在前后端数据对介绍会涉及到跨域问题,接口文档对接问题,因此需要简单编写一下跨域,Swagger的配置类。

package com.yy.Config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

/**
 * @author young
 * @date 2022/8/23 17:33
 * @description: 跨域配置
 */
@Configuration
public class CorsConfig {
    /**
     * 最大有效时长
     */
    private static final  long MAX_TIMEOUT=24*60*60;
    @Bean
    public CorsConfiguration corsConfiguration(){
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setMaxAge(MAX_TIMEOUT);
        //设置访问源请求头
        corsConfiguration.addAllowedHeader("*");
        //设置访问源地址
        corsConfiguration.addAllowedOrigin("*");
        //设置访问源请求方法
        corsConfiguration.addAllowedMethod("*");
        return corsConfiguration;
    }

    /**
     * 设置跨域配置
     * @return
     */
    @Bean
    public CorsFilter corsFilter(){
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**",corsConfiguration());
        return new CorsFilter(source);
    }
}
package com.yy.Config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.env.Profiles;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.util.ArrayList;

@Configuration
@EnableSwagger2//开启Swagger2
public class SwaggerConfig {

    //添加分组
    @Bean
    public Docket docket1(){
        return new Docket(DocumentationType.SWAGGER_2).groupName("黎治跃");
    }

    //配置Swagger的Docket的bean实例
    @Bean
    public Docket docket(Environment environment){

        //设置要显示的Swagger环境
        Profiles profiles = Profiles.of("dev", "test");
        //获取项目环境
        boolean b = environment.acceptsProfiles(profiles);
        System.out.println(b);

        return new Docket(DocumentationType.SWAGGER_2).groupName("YY")
            .apiInfo(apiInfo())
            .enable(b)  //是否启动Swagger,false,则浏览器无法访问Swagger
            .select()
            //RequestHandlerSelectors,配置要扫描的接口方式
            //basePackage指定要扫描的包
            //any : 扫描全部
            //none :不扫描
            //withClassAnnotation : 扫描类上的注解
            .apis(RequestHandlerSelectors.basePackage("com.yy.controller"))
            //path :过滤路径
            //.paths(PathSelectors.ant("/yy/**"))
            .build();
}

//配置Swagger信息=apiinfo

    private ApiInfo apiInfo(){
        Contact contact = new Contact("YY", "https://www.4399.com", "2463252763@qq.com");
        return new ApiInfo("YY的SwaggerAPI文档", 
            "黎治跃失恋了,2022/8/19",
            "1.0v",
            "urn:tos",
             contact, 
            "Apache 2.0", 
            "http://www.apache.org/licenses/LICENSE-2.0",
            new ArrayList<>());
    }
}

为了更好地清晰的让我们获取的信息与前端统一,也可以编写一个统一返回值的类,让返回结果以自定义的JSON格式展示出来,方便我们阅读。

 定义一个方便获取常量的枚举类

/**
 * @author young
 * @date 2022/8/19 21:36
 * @description: 响应结果枚举类
 */

@AllArgsConstructor
@Getter
public enum ResponseEnum {
   /**响应成功**/
   SUCCESS(200, "操作成功"),
   /**操作失败*/
   FAIL(201,"获取数据失败"),
   /**错误请求**/
   ERROR(400,"错误请求"),
   /**页面未找到**/
   NOT_FOUND(404,"页面未找到"),
   /**系统异常**/
   SYS_ERROR(-1,"系统异常"),
  /*信息已存在*/
  MSG_ERROR(409,"信息已存在");
   /**响应码**/
   private final Integer code;
   
   /** 结果 **/
   private  final String  resultMessage;
   
   public static ResponseEnum getResultCode(Integer code){
      for (ResponseEnum value : ResponseEnum.values()) {
         if (code.equals(value.getCode())){
            return value;
         }
      }
      return ResponseEnum.ERROR;
   }
/*
简单测试一下
 */
   public static void main(String[] args) {
      ResponseEnum resultCode = ResponseEnum.getResultCode(100);
      System.out.println(resultCode);
   }
}

定义统一返回值的类 

package com.yy.utils;
import com.yy.enums.ResponseEnum;
import lombok.Data;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

/**
 * @author young
 * @date 2022/8/19 21:52
 * @description: 统一返回结果的类
 */

@Data
public class  R<T> implements Serializable {
    
    private static final long serialVersionUID = 56665257248936049L;
    /**响应码**/
    private Integer code;

    /**返回消息**/
    private String message;

    /**返回数据**/
    private T data;

   private R(){}
    /**
     * 操作成功ok方法
     */
    public static <T> R<T> ok(T data) {

        R<T> response = new R<>();
        response.setCode(ResponseEnum.SUCCESS.getCode());
        response.setMessage(ResponseEnum.SUCCESS.getResultMessage());
        response.setData(data);
        return response;
    }

    /**
     * 编译失败方法
     */
    public static <T> R<T> buildFailure(Integer errCode, String errMessage){

        R<T> response = new R<>();
        response.setCode(errCode);
        response.setMessage(errMessage);
        return response;
    }

}

 如果需要在后端对获取的响应数据用mybatis-plus进行分页呢。还需要配置一下mybatis-plus的配置类

/**
 * @author young
 * @date 2022/8/29 21:27
 * @description: MyBatis-Plus分页配置
 */
@Configuration
@MapperScan("com.yy.dao")
public class MyBatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){

        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
        // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求  默认false
        // paginationInnerInterceptor.setOverflow(false);
        // 设置最大单页限制数量,默认 500 条,-1 不受限制
        // paginationInnerInterceptor.setMaxLimit(500L);
        interceptor.addInnerInterceptor(paginationInnerInterceptor);
        return interceptor;

    }
}

当然,这个并不是必须的,后面在前端通过element-plus也能对数据自动进行分页展示,个人认为更加方便,没有必要在后端进行分页。如果是为了更好的按条件查询或其他之用,也可以考虑 。

2.1.6,编写controller去提取前端页面需要的数据

/**
 * @author young
 * @date 2022/8/26 9:36
 * @description:
 */
@Slf4j
@RestController
@RequestMapping("/mysql")
public class TestUserController {
    private static final DateFormat dataFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    @Resource
    private TestUserServiceImpl testUserService;
/*                            前后端分离测试                    */

    /**
     * 添加用户
     *
     * @param request
     * @return
     */
    @PostMapping("/addUserTo")
    public R<Object> addUser(HttpServletRequest request) {
        JSONObject object = new JSONObject();
        String name = request.getParameter("name").trim();
        String sex = request.getParameter("sex").trim();
        String address = request.getParameter("address").trim();
        String createTime = request.getParameter("createTime").trim();
        if ("".equals(name)) {
            object.put("code", 0);
            object.put("msg", "用户不能为空");
            return R.ok(object);
        }
        TestUser user = new TestUser();
        Date date = new Date();
        try {
            date = dataFormat.parse(createTime);
        } catch (Exception e) {
            e.printStackTrace();
        }
        user.setName(name);
        user.setSex(Boolean.valueOf(sex));
        user.setAddress(address);
        user.setCreateTime(date);
        try {
            boolean add = testUserService.save(user);
           
            if (add) {
                object.put("code", 1);
                object.put("success", true);
                object.put("msg", "添加成功");
                object.put("type", "success");
                return R.ok(object);
            } else {
                object.put("code", 0);
                object.put("success", false);
                object.put("msg", "添加失败");
                object.put("type", "error");
                return R.buildFailure(ResponseEnum.FAIL.getCode(), ResponseEnum.FAIL.getResultMessage());
            }
        } catch (DuplicateKeyException e) {
            object.put("code", 2);
            object.put("success", false);
            object.put("msg", "用户已存在");
            object.put("type", "error");
            return R.buildFailure(ResponseEnum.MSG_ERROR.getCode(), ResponseEnum.MSG_ERROR.getResultMessage());
        }
    }

    /**
     * 前端获取所有数据
     *
     * @return
     */
    @GetMapping("/getAllTo")
    public R<List<TestUser>> allUser() {
        return R.ok(testUserService.list());
    }

    /**
     * 返回指定id的用户
     *
     * @param request
     * @return
     */
    @GetMapping("/getById")
    public R<TestUser> getById(HttpServletRequest request) {
        String id = request.getParameter("id");
        TestUser user = testUserService.getById(id);
        return R.ok(user);
    }

    /**
     * 删除用户
     *
     * @param request
     * @return
     */
    @DeleteMapping("deleteUserTo")
    public R<Boolean> deleteUserTo(HttpServletRequest request) {
        String id = request.getParameter("id");
        return R.ok(testUserService.removeById(id));
    }

    /**
     * 更新用户信息
     *
     * @param request
     * @return
     */
    @PostMapping("/updateUserTo")
    public R<Object> updateUserTo(HttpServletRequest request) {
        JSONObject jsonObject = new JSONObject();
        String id = request.getParameter("id").trim();
        String name = request.getParameter("name").trim();
        String sex = request.getParameter("sex").trim();
        String address = request.getParameter("address").trim();
        String createTime = request.getParameter("createTime").trim();
        TestUser testUser = new TestUser();
        Date date = new Date();
        try {
            date = dataFormat.parse(createTime);
        } catch (Exception e) {
            e.printStackTrace();
        }
        testUser.setId(Integer.parseInt(id));
        testUser.setName(name);
        testUser.setSex(Boolean.valueOf(sex));
        testUser.setAddress(address);
        testUser.setCreateTime(date);
        boolean res = testUserService.updateById(testUser);
        if (res) {
            jsonObject.put("code", 1);
            jsonObject.put("msg", "修改成功!");
             R.ok(jsonObject).toString();
            return R.ok(jsonObject);
        } else {
            jsonObject.put("code", 0);
            jsonObject.put("msg", "修改失败");
            return R.buildFailure(ResponseEnum.FAIL.getCode(), ResponseEnum.FAIL.getResultMessage());
        }
    }
}

最后,通过接口测试工具(Swagger,ApiPost,Postman都可)对我们写的数据接口测试一下,数据返回值符合预期的话,那么后端代码就该一段落了!

2.2,前端部分

前端主要通Vue框架构建项目,主要是对客户端界面进行构造。由于笔者对于前端基础不怎么好,因此主要用Element-Plus进行界面构造,axios解决前后端交互。vue使用的是vue3,但是函数方法上仍旧采用的vue2的形式,主要实现过程如下:

2.2.1,在main.js上全局配置需要使用到的插件

import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'
import * as ELIcons from '@element-plus/icons-vue'
// 配置路由器
import router from './router'

import './assets/global.css'
createApp(App).use(router).use(ELIcons).use(ElementPlus,{size:'small'}).mount('#app')

2.2.2,封装aixos请求后端的请求方式request.js

import axios from 'axios'
import {BASE_URL} from '../util/name'

axios.defaults.timeout = 5000 // 超时时间设置
axios.defaults.baseURL = BASE_URL
// Content-Type 响应头
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'

// response 拦截器
// 可以在接口响应后统一处理结果
axios.interceptors.response.use(
    response => {
        let res = response.data;
        // 如果是返回的文件
        if (response.config.responseType === 'blob') {
            return res
        }
        // 兼容服务端返回的字符串数据
        if (typeof res === 'string') {
            res = res ? JSON.parse(res) : res
        }
        return res;
    }
    ,
    error => {
        console.log('err' + error) // for debug
        return Promise.reject(error)
    }
)


/**
   * 封装get方法
   * @param url
   * @param data
   * @returns {Promise}
   */
 export function get (url, params = {}, responseType = 'json') {
    return new Promise((resolve, reject) => {
      axios.get(url, {
        params: params,
        responseType
      })
        .then(response => {
          resolve(response.data)
        })
        .catch(err => {
          reject(err)
        })
    })
  }
  
  /**
     * 封装post请求
     * @param url
     * @param data
     * @returns {Promise}
     */
  export function post (url, data = {}) {
    return new Promise((resolve, reject) => {
      axios.post(url, data)
        .then(response => {
          resolve(response.data)
        }, err => {
          reject(err)
        })
    })
  }
  
  /**
     * 封装delete请求
     * @param url
     * @param data
     * @returns {Promise}
     */
  export function deletes (url, data = {}) {
    return new Promise((resolve, reject) => {
      axios.delete(url, data)
        .then(response => {
          resolve(response.data)
        }, err => {
          reject(err)
        })
    })
  }

2.2.3,封装前后端api对应的请求接口index.js

import {get,post,deletes} from '../util/request'
const HttpManager={

  // 前端用到的函数            后端对应的接口
   //返回所有用户 
  getAllUser: () => get(`mysql/getAllTo`),
  // 返回指定ID的用户
  getUserOfId: (id) => get(`mysql/getById?id=${id}`),
  // 添加用户
  addUser: (params) => post(`mysql/addUserTo`, params),
  // 更新用户信息
  updateUserMsg: (params) => post(`mysql/updateUserTo`, params),
  // 删除用户
  deleteUser: (id) => deletes(`mysql/deleteUserTo?id=${id}`),
  //模糊查询
  likeSelect:(params)=>get(`mysql/likeSelect`,params)
}
export {HttpManager} 

2.2.4,提取公共的methos,放在mixins中,这样就能将共用的功能以对象的方式传入 mixins选项中,当组件使用 mixins对象时所有mixins对象的选项都将被混入该组件本身的选项中来,这样就可以提高代码的重用性,使代码保持干净和易于维护。

<!--mixins/index.js-->

export const mixin = {
  methods: {
    // 获取要删除列表的id
    handleDelete (id) {
      this.idx = id
      this.delVisible = true
    },
    // 获取批量要删除的列表
    handleSelectionChange (val) {
      this.multipleSelection = val
    },
    // 批量删除
    delAll () {
      console.log("执行该方法")
      for (let item of this.multipleSelection) {
        this.handleDelete(item.id)
        this.deleteRow(item.id)
      }
      this.multipleSelection = []
    },
    getTime (val) {
      let time = String(val).match(/[0-9-]+(?=\s)/)
      return Array.isArray(time) ? time[0] : time
    },
    changeSex (value) {
      if (value === false) {
        return '女'
      } else if (value === true) {
        return '男'
      }
    },
    toggleSex (value) {
      if (value === '女') {
        return false
      } else if (value === '男') {
        return true
      }
    },
    // 更新图片
    handleAvatarSuccess (res, file) {
      if (res.code === 1) {
        this.imageUrl = URL.createObjectURL(file.raw)
        this.getData()
        this.$notify({
          title: '上传成功',
          type: 'success'
        })
      } else {
        this.$notify({
          title: '上传失败',
          type: 'error'
        })
      }
    },
    beforeAvatarUpload (file) {
      const isJPG = (file.type === 'image/jpeg') || (file.type === 'image/png')
      const isLt2M = file.size / 1024 / 1024 < 2
      if (!isJPG) {
        this.$message.error('上传头像图片只能是 JPG 格式!')
      }
      if (!isLt2M) {
        this.$message.error('上传头像图片大小不能超过 2MB!')
      }
      return isJPG && isLt2M
    },

  }
}

 2.2.5,抽离出侧边栏组件AsiderBody,头部组件HeaderBody,直接从官网提取,并进行简单的样式更改

<!--HeaderBody.vue -->
<template>
   <!-- 收缩 -->
   <div  style="font-size: 14px;line-height: 60px; display: flex">
        <div style="flex: 1;font-size: 20px">
          <el-icon style="cursor: pointer" @click="collapse"><Fold /></el-icon>
        </div>
        <div class="toolbar" style="width: 70px">
          <el-dropdown style="cursor: pointer">
            <el-icon style="margin-right: 8px; margin-top: 24px"
              ><ArrowDown
            /></el-icon>
            <template #dropdown>
              <el-dropdown-menu>
                <el-dropdown-item>个人信息</el-dropdown-item>
                <el-dropdown-item>退出</el-dropdown-item>
              </el-dropdown-menu>
            </template>
          </el-dropdown>
          <span>张三</span>
        </div>
   </div>
</template>

<script>
import {Fold,ArrowDown} from '@element-plus/icons-vue'
export default {
name:'HeaderBody',
components:{
Fold,
ArrowDown
},
props:['collapse'],
}
</script>

<style>

</style>
<!--AsiderBody.vue -->
<template>
  <el-scrollbar style="background-color: #304156">
    <el-menu
      :default-openeds="['1', '3']"
      background-color="#304156"
      text-color="rgb(91, 119, 211)"
      active-text-color="#ffd04b"
      overflow="hidden"
      :collapse="isCollapse"
      :collapse-transition="false"
      router
    >
      <!-- 添加头部log -->
      <div style="height: 60px; line-height: 60px; text-align: center">
        <img
          src="../assets/yp.png"
          style="width: 20px; posotion: relative; top: 5px; margin-right: 5px"
        />
        <b style="color: white" v-show="logoTestShow">后台管理系统</b>
      </div>
      <el-sub-menu index="/">
        <template #title>
          <el-icon><Menu /></el-icon><span>导航 主页</span>
        </template>
        <el-menu-item-group>
          <template #title>分组 1</template>
          <el-menu-item index="/user">用户管理 1</el-menu-item>
          <el-menu-item index="/about">关于-登录</el-menu-item>
        </el-menu-item-group>
        <el-menu-item-group title="分组 2">
          <el-menu-item index="1-3">选项 3</el-menu-item>
        </el-menu-item-group>
        <el-sub-menu index="1-4">
          <template #title>选项4</template>
          <el-menu-item index="1-4-1">选项 4-1</el-menu-item>
        </el-sub-menu>
      </el-sub-menu>
      <el-sub-menu insdex="2">
        <template #title>
          <el-icon><Message /></el-icon>
          <span>导航 Two</span>
        </template>
        <el-menu-item-group>
          <template #title>分组 1</template>
          <el-menu-item index="2-1">选项 1</el-menu-item>
          <el-menu-item index="2-2">选项 2</el-menu-item>
        </el-menu-item-group>
        <el-menu-item-group title="Group 2">
          <el-menu-item index="2-3">选项 3</el-menu-item>
        </el-menu-item-group>
        <el-sub-menu index="2-4">
          <template #title>选项 4</template>
          <el-menu-item index="2-4-1">选项 4-1</el-menu-item>
        </el-sub-menu>
      </el-sub-menu>
      <el-sub-menu index="3">
        <template #title>
          <el-icon><House /></el-icon>
          <span>导航 Three</span>
        </template>
        <el-menu-item-group>
          <template #title>分组 1</template>
          <el-menu-item index="3-1">选项 1</el-menu-item>
          <el-menu-item index="3-2">选项 2</el-menu-item>
        </el-menu-item-group>
        <el-menu-item-group title="Group 2">
          <el-menu-item index="3-3">选项 3</el-menu-item>
        </el-menu-item-group>
        <el-sub-menu index="3-4">
          <template #title>选项 4</template>
          <el-menu-item index="3-4-1">选项 4-1</el-menu-item>
        </el-sub-menu>
      </el-sub-menu>
    </el-menu>
  </el-scrollbar>
</template>

<script>
import { Menu, Message, House } from "@element-plus/icons-vue";
export default {
  name: "AsiderBody",
  props: {
    isCollapse: Boolean,
    logoTestShow: Boolean,
  },
  components: {
    Menu,
    Message,
    House,
  },
};
</script>

<style>
</style>

2.2.6,构建主要的信息展示界面,这样只有el-main里面的内容会随路由的改变而切换,而侧边栏AsiderBody,头部栏HeaderBody不会改动,从而实现组件复用。

<!--HomePage.vue-->
<template>
  <el-container class="layout-container-demo" style="height: 100vh">
    <el-aside :width="sideWidth + 'px'" background-color="rgb(238,241,246)">
    <asider-body :isCollapse="isCollapse" :logoTestShow="logoTestShow" :collapse="collapse"/>
    </el-aside>

    <el-container>
      <el-header style="border-bottom:1px solid #ccc">
       <HeaderBody :collapse="isCollapse"/>
      </el-header>

      <el-main style="margin-left: 40px">
       <router-view/>
      </el-main>
    </el-container>
  </el-container>
</template>

<script>

import { mixin } from "../mixins/index";
import AsiderBody from "@/components/AsiderBody.vue"
import HeaderBody from "@/components/HeaderBody.vue"
export default {
  name: "HomePage",
  mixins: [mixin],
  components: {
    AsiderBody,
    HeaderBody
  },
  data() {
    return {
      isCollapse: false,
      sideWidth: 200,
      logoTestShow: true,
    }
  },
  methods:{
            // 收缩侧边栏
    collapse() {
      this.isCollapse = !this.isCollapse;
      if (this.isCollapse) {
        (this.sideWidth = 64), (this.logoTestShow = false);
      } else {
        (this.sideWidth = 200), (this.logoTestShow = true);
      }
    },
}
}
</script>

<style scoped>
.layout-container-demo .el-header {
  position: relative;
  background-color: var(--el-color-primary-light-7);
  color: var(--el-text-color-primary);
}
.layout-container-demo .el-aside {
  color: var(--el-text-color-primary);
  background: var(--el-color-primary-light-8);
}
.layout-container-demo .el-menu {
  border-right: none;
}
.layout-container-demo .el-main {
  padding: 0;
}
.layout-container-demo .toolbar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  right: 20px;
}

</style>

2.2.7,用户信息展示界面构造,以及相关函数编写调用

<!--UserMsg.vue-->
<template>
  <div>
       <div style="margin-top: 20px; text-size: 20px">
          <el-breadcrumb separator="/">
            <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
            <el-breadcrumb-item
              ><a href="/user">用户信息</a></el-breadcrumb-item
            ></el-breadcrumb
          >
        </div>
        <div style="margin-top: 10px">
          <el-input
            v-model="select_word"
            placeholder="筛选相关用户"
            style="width: 200px"
          >
            <template #suffix>
              <el-icon><Search /></el-icon>
            </template>
          </el-input>
          <el-button
            round
            color="#db6b2b"
            class="ml-5"
            plain
            @click="reSet"
          >
            重置</el-button
          >
        </div>
        <div style="padding: 10px 0; display: inline-flex">
          <el-button type="primary" @click="delAll"
            >批量删除
            <el-icon><DeleteFilled /></el-icon>
          </el-button>
          <el-button
            type="primary"
            class="mr-5"
            @click="centerDialogVisible = true"
          >
            添加用户<el-icon><Plus /></el-icon>
          </el-button>
          <el-upload
            ref="upload"
            action="#"
            accept=".xlsx, .xls"
            :auto-upload="false"
            :on-change="uploadFile"
            :show-file-list="false"
          >
            <el-button type="primary" class="ml-5">
              导入数据<el-icon><Download /></el-icon>
            </el-button>
          </el-upload>
          <el-button
            type="primary"
            style="margin-left: 10px"
            @click="exportE()"
          >
            导出数据<el-icon><Upload /></el-icon>
          </el-button>
        </div>
        <el-table
          :data="datas"
          style="text-align: center"
          border
          stripe
          @selection-change="handleSelectionChange"
        >
          <el-table-column
            type="selection"
            width="40"
            align="center"
          ></el-table-column>
          <el-table-column prop="id" label="ID" width="80px" align="center" />
          <el-table-column
            prop="createTime"
            label="日期"
            width="240px"
            align="center"
          >
            <!-- <template v-slot="scope">
              <div>{{ getTime(scope.row.createTime) }}</div>
            </template> -->
          </el-table-column>
          <el-table-column
            prop="name"
            label="姓名"
            width="200px"
            align="center"
          />
          <el-table-column prop="sex" label="性别" width="200px" align="center">
            <!--  eslint-disable-next-line -->
            <template v-slot="scope">
              <div>{{ changeSex(scope.row.sex) }}</div>
            </template>
          </el-table-column>
          <el-table-column
            prop="address"
            label="地址"
            width="200px"
            align="center"
          />
          <el-table-column label="操作" align="center">
            <!-- 解决scope没被使用的问题 -->
            <!--  eslint-disable-next-line -->
            <template v-slot="scope">
              <el-button
                type="success"
                class="mr-5"
                @click="handleEdit(scope.row)"
                >编辑<el-icon><Edit /></el-icon
              ></el-button>
              <el-button
                type="danger"
                class="mr-5"
                @click="handleDelete(scope.row.id)"
                >删除<el-icon><DeleteFilled /></el-icon
              ></el-button>
              <el-button type="warning" class="mr-5"
                >权限<el-icon><ElementPlus /></el-icon
              ></el-button>
            </template>
          </el-table-column>
        </el-table>
        <div style="padding: 10px 0">
          <el-pagination
            @current-change="handleCurrentChange"
            background
            layout="total, prev, pager, next"
            :current-page="currentPage"
            :page-size="pageSize"
            :total="tableData.length"
          >
          </el-pagination>
        </div>
        <!--添加新用户-->
        <el-dialog
          title="添加用户"
          v-model="centerDialogVisible"
          width="400px"
          center
        >
          <el-form
            :model="registerForm"
            status-icon
            :rules="rules"
            ref="registerForm"
            label-width="70px"
            class="demo-ruleForm"
          >
            <el-form-item label="用户名" prop="name" size="small">
              <el-input
                v-model="registerForm.name"
                placeholder="用户名"
              ></el-input>
            </el-form-item>
            <el-form-item label="性别" size="small">
              <el-radio-group v-model="registerForm.sex">
                <el-radio :label="false">女</el-radio>
                <el-radio :label="true">男</el-radio>
              </el-radio-group>
            </el-form-item>
            <el-form-item label="创建时间" prop="createTime" size="small">
              <el-date-picker
                type="date"
                placeholder="选择日期"
                v-model="registerForm.createTime"
                style="width: 100%"
              ></el-date-picker>
            </el-form-item>
            <el-form-item label="地址" prop="address" size="small">
              <el-input
                v-model="registerForm.address"
                placeholder="地址"
              ></el-input>
            </el-form-item>
          </el-form>
          <template #footer>
            <span class="dialog-footer">
              <el-button size="small" @click="centerDialogVisible = false"
                >取 消</el-button
              >
              <el-button type="primary" size="small" @click="addPeople"
                >确 定</el-button
              >
            </span>
          </template>
        </el-dialog>
        <!-- 编辑弹出框 -->
        <el-dialog title="编辑" v-model="editVisible" width="400px">
          <el-form ref="form" :model="form" label-width="60px">
            <el-form-item label="用户名" size="small">
              <el-input v-model="form.name" :disabled="true"></el-input>
            </el-form-item>

            <el-form-item label="性别" size="small">
              <el-radio-group v-model="form.sex">
                <el-radio :label="false">女</el-radio>
                <el-radio :label="true">男</el-radio>
              </el-radio-group>
            </el-form-item>

            <el-form-item label="创建日期" prop="createTime" size="small">
              <el-date-picker
                type="date"
                placeholder="选择日期"
                v-model="form.createTime"
                style="width: 100%"
              ></el-date-picker>
            </el-form-item>
            <el-form-item label="地址" size="small">
              <el-input v-model="form.address"></el-input>
            </el-form-item>
          </el-form>
          <template #footer>
            <span class="dialog-footer">
              <el-button size="small" @click="editVisible = false"
                >取 消</el-button
              >
              <el-button type="primary" size="small" @click="saveEdit"
                >确 定</el-button
              >
            </span>
          </template>
          <!-- 删除提示框 -->
        </el-dialog>
        <DelDialog
          :delVisible="delVisible"
          @deleteRow="deleteRow"
          @cancelRow="delVisible = $event"
        ></DelDialog>
  </div>
</template>

<script>
import { HttpManager } from "../api/index";
import { getDateTime } from "../util/DataUtil";
import DelDialog from "@/components/DelDialog.vue";
import { mixin } from "../mixins/index"; 
import {
  Plus,
  Upload,
  Download,
  Search,
  Edit,
  DeleteFilled,
  ElementPlus,
} from "@element-plus/icons-vue";
export default {
name:'UserMsg',
mixins: [mixin],
components:{
     Plus,
    Upload,
    Download,
    Search,
    Edit,
    DeleteFilled,
    ElementPlus,
    DelDialog,
},
 data() {
    return {
      tableData: [],
      multipleSelection: [], // 记录要删除的用户信息
      centerDialogVisible: false,
      editVisible: false, // 显示编辑框
      delVisible: false, // 显示删除框
      select_word: "", // 记录输入框输入的内容
      pageSize: 10, // 页数
      currentPage: 1, // 当前页
      idx: -1, // 记录当前点中的行
      tempDate: [],
      is_Search: false,
      excelVisible: false,
      registerForm: {
        // 添加用户
        name: "",
        sex: "",
        createTime: "",
        address: "",
      },
      form: {
        // 记录编辑的信息
        id: "",
        name: "",
        sex: "",
        createTime: "",
        address: "",
        //updateTime: ''
      },
    };
  },
  computed: {
    // 计算当前表格中的数据
    datas() {
      return this.tableData.slice(
        (this.currentPage - 1) * this.pageSize,
        this.currentPage * this.pageSize
      );
    },
  },
  //模糊查询
  watch: {
    select_word() {
      if (this.select_word === "") {
        this.tableData = this.tempDate;
      } else {
        this.tableData = [];
        for (let item of this.tempDate) {
          if (item.name.includes(this.select_word) ) 
            {
            this.tableData.push(item);
          }
        }
      }
    },
  },
  created() {
    //获取分页数据信息
    this.getData();
  },
  methods: {
    // 获取用户信息
    getData() {
      this.tableData = [];
      this.tempDate = [];
      HttpManager.getAllUser().then((res) => {
        this.tableData = res;
        this.tempDate = res;
        this.currentPage = 1;
        console.log(this.tempDate)
      });
    },
    //重置搜索信息
    reSet() {
      this.select_word = "";
      this.getData();
    },

    // 添加用户
    addPeople() {
      let createTime = getDateTime(this.registerForm.createTime);
      let params = new URLSearchParams();
      params.append("name", this.registerForm.name);
      params.append("sex", this.registerForm.sex);
      params.append("createTime", createTime);
      params.append("address", this.registerForm.address);
      HttpManager.addUser(params)
        .then((res) => {
          if (res.code === 1) {
            this.getData();
            this.registerForm = {};
            this.$notify({
              title: "添加成功",
              type: "success",
            });
          } else {
            this.$notify({
              title: "添加失败",
              type: "error",
            });
          }
        })
        .catch((err) => {
          console.error(err);
        });
      this.centerDialogVisible = false;
    },
    // 分页
    // handleSizeChange(pageSize) {
    //   console.log(`每页 ${pageSize} 条`);
    //   this.pageSize = pageSize;
    //  // this.getData();
    // },
    handleCurrentChange(val) {
      this.currentPage = val;
    },

    // 编辑
    handleEdit(row) {
      this.idx = row.id;
      this.form = {
        id: row.id,
        name: row.name,
        sex: row.sex,
        createTime: row.createTime,
        address: row.address,
      };
      this.editVisible = true;
    },
    // 保存编辑
    saveEdit() {
      let datetime = getDateTime(new Date(this.form.createTime));
      let params = new URLSearchParams();
      params.append("id", this.form.id);
      params.append("name", this.form.name);
      params.append("sex", this.form.sex);
      params.append("createTime", datetime);
      params.append("address", this.form.address);
      HttpManager.updateUserMsg(params)
        .then((res) => {
          if (res.code === 1) {
            this.getData();
            this.$notify({
              title: "修改成功",
              type: "success",
            });
          } else {
            this.$notify({
              title: "修改失败",
              type: "error",
            });
          }
        })
        .catch((err) => {
          console.error(err);
        });
      this.editVisible = false;
    },
    // 确定删除
    deleteRow() {
      HttpManager.deleteUser(this.idx)
        .then((res) => {
          if (res) {
            this.getData();
            this.$notify({
              title: "删除成功",
              type: "success",
            });
          } else {
            this.$notify({
              title: "删除失败",
              type: "error",
            });
          }
        })
        .catch((error) => {
          console.error(error);
        });
      this.delVisible = false;
    },
  },
};
</script>

<style>
/* 分页 */
.demo-pagination-block + .demo-pagination-block {
  margin-top: 10px;
}
.demo-pagination-block .demonstration {
  margin-bottom: 16px;
}
</style>

2.2.8,简单配置一下router,这样运行项目后,localhst:8080访问进入到“/home”请求对应的组件界面(随便写一个即可)上,点击侧边栏上的用户管理就能跳转到对应的信息展示界面。

import { createRouter, createWebHistory } from 'vue-router'
import HomePage from '@/view/HomePage'

const routes = [
  {
    path: '/',
    name: 'HomePage',
    component: HomePage,
    redirect: '/home',
    children: [
      {
        path: 'home',
        name: 'HomeTest',
        component: () => import('../components/HomeTest.vue')
      },
      {
        path: 'user',
        name: 'UserMsg',
        component: () => import('../view/UserMsg.vue')
      },
      {
        path: 'about',
        name: 'About',
        component: () => import('../components/AboutTest.vue')
      },
    ]
  },
]

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes
})
export default router

2.2.9,在vue.config.js上通过chainWebpack配置后端代理地址,这样由于后端已经配置了跨域,前端就可以通过对后端的请求访问到后端对应的接口了。

const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,
  chainWebpack: config => {
    config.plugin('define').tap(definitions => {
        Object.assign(definitions[0]['process.env'], {
          NODE_HOST: '"http://localhost:8090"',
        });
        return definitions;
    });
  }
})

2.3,项目运行及实现结果

前端通过 npm install 安装项目所需的依赖,然后npm run serve运行项目即可得到初始的HomePage界面。因为前端学的并不扎实,页面配色布局可能一言难尽……

展开导航主页,点击用户展示界面,得到相应界面,此时并没有数据展示,只有初始的一些界面 ,因为后端服务没有开启,数据获取不到。

 运行后端项目,重新刷新一下前端界面,数据通过element-plus中的el-pagination分页插件已经实现了分页效果。

并且该能实现一些基本增删改查操作,后端数据库的信息也会相应进行更改!

至此,简单的数据交互就实现了。 

四,简单总结 

这个测试项目还有一些小BUG正在完善中,还有一些实现的功能并没有完全放在博客中,这篇文章仅限于展示一些数据,实现前后端数据之间的交互。后期会继续完善成为一个简易的后台管理系统,供学习练习之用,项目会陆续上传到GitHub/Gitee上……有问题的地方希望大家指正交流,共同进步。

补充:

gitee项目地址

由于项目中涉及一些mysql以及mongodb的数据库,但是考虑比较简单,只是作为数据模拟使用的,因此没有放在项目中,前端也比较较简单没有放在gitee中,大家自行构建。

vue简单的前后端交互示例详解
12-09
一、学习 vue 面临的题 最近想学一门前端技术防身,看到博客园中写 vue 的多,那就 vue 吧。都说 vue 的官方教程写得好,所以我就从官方教程开始学习。官方教程说“Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。”但是这个概念是个什么鬼?还是让人一头雾水嘛。而且我一开始也没有搞清楚 vue 的定位,只知道它是一个前端库,但是确实不知道它的优势是什么,还以为它是一个学会就能一劳永逸的万能的框架呢。官方教程一开始就讲怎么绑定页面上的元素和 JavaScript 中的数据,而且是双向绑定,
使用springboot+mybatis+Vue2.0+elementUI实现简单的登录注册及用户信息获取。
07-09
本demo适合刚入门学习SpringBootVue的小伙伴,要求有SSM基础,较熟悉web应用三层架构,且对前端的html\css\js有一定的基础,会写ajax等基础的前后端交互请求。 本demo实现简单的登录、注册、获取用户信息三个功能,其中包含密码加密,解决了前后端分离项目常见的跨域题及session题,界面清晰简单,后台分层清晰,逻辑清楚。 值得一看。 项目结构:ajax_test为后端项目,ajax_t为前端项目,同时在idea启动即可,另外sql文件数据库表sql,温馨提醒:记得在yml中修数据库配置哦! 阅读建议:安装好Vue及相关的elementUI、axios等环境,会使用vueCli及springboot初始化项目,能将项目跑起来,直接看到效果。 有题随时私信联系哦!一起交流。
Java项目:企业人事系统(java+SpringBoot+Vue+ElementUI+maven+mysql)
05-26
项目介绍 人事管理系统功能包括人事通讯,员工信息,人事考评,奖惩,培训管理,薪资管理,统计分析,和系统管理六大模块,对应人事工作基本流程:新员工入职档案建立,调动,辞职,员工信息的查询及工资管理等方面.系统管理可以根据不同的角色分配菜单权限设置,不同的用户授予不同角色,对人事结构,单位结构进行整体调配设置.在线聊天可以实现操作员之间讯息的及时通讯. 项目基于MVVM的前后端分离开发模式进行开发.MVVM即模型(Model)-视图(View)-视图模型(View Model),实现数据视图的双向绑定.相对于MVC模式和MVP来说,MVVM是一个比较新的开发架构,它是一种将MVP模式与WPF相结合应用方式发展演变而成的新型开发架. 前后端分离是指将前端和后端从之前的全部由后端负责中分离开来,不再共用一个Server,前端作为一个独立Serve存在.前后端通过接口使用HTTP协议交互,本项目使用vu实体属性outer做前端路由处理.页面跳转不在由后端处理,前后端只是数据交互.前后端分离的好处在于降低了前后端的耦合性.当面对不同的硬件场景时,需要构建不同的界面,前后端分离之后,只需要扩展
基于SpringBoot+Vue实现前后端交互功能(详解Vue框架机制)
a910247的博客
03-26 2430
Vue框架知多少?Vue.js(通常简称为Vue)是一种流行的JavaScript前端框架,用于构建交互式的用户界面和单页面应用(SPA)。Vue由尤雨溪(Evan You)于2014年创建,并于同年正式发布。它的设计目标是通过尽可能简单的API提供高效的响应式数据绑定和组件化的视图组织方式。
VUE前后端分离数据交互简单项目作为演示)
热门推荐
weixin_45928161的博客
03-11 2万+
文章目录一、添加后端访依赖二、建立后端三、配置前端 提示:这里重点演示前端如何访后端,对于前、后端的建立不作为重点 一、添加后端访依赖 进入前端vue项目,进入内部或外部终端 输入如下代码并安装 cnpm install axios --save cnpm install qs --save 安装好之后可以在package.json中看到添加的依赖 在main.js中引入添加的依赖(main,js中存储组件的公共依赖,在此文件中添加依赖后无需再在各组件文件里单独添加依赖) 引入
基于SpringBoot+Vue开发的前后端分离外卖点单系统源码+数据库+项目说明.zip
01-08
【资源说明】 1、基于SpringBoot+Vue开发的前后端分离外卖点单系统源码+数据库+项目说明.zip 2、该资源包括项目的全部源码,下载可以直接使用! 3、本项目适合作为计算机、数学、电子信息等专业的课程设计、期末大作业和毕设项目,作为参考资料学习借鉴。 4、本资源作为“参考资料”如果需要实现其他功能,需要能看懂代码,并且热爱钻研,自行调试。 基于SpringBoot+Vue开发的前后端分离外卖点单系统源码+数据库+项目说明.zip 基于SpringBoot+Vue开发的前后端分离外卖点单系统源码+数据库+项目说明.zip ## 目录结构 后台前端项目位于renren-ui下 小程序前端项目位于takeout_mp下 SQL文件位于根目录下的takeout_mysql8.sql,需要MYSQL8以上版本。 **ps:请先运行后端项目,再启动前端项目。** ``` take_out │ ├─renren-admin 美食元素后台管理后端服务 │ │ │ │ │ ├─modules 模块 │ │ ├─job 定时任务 │ │ ├─log 日志管理 │ │ ├─oss 文件存储 │ │ ├─security 安全模块 │ │ ├─sys 系统管理(核心) | | └─takeout 外卖业务模块(核心) │ │ │ └─resources │ ├─mapper MyBatis文件 │ ├─public 静态资源 │ └─application.yml 全局配置文件 │ │ ├─renren-api 美食元素小程序后端服务 │ ├─renren-common 公共模块 ├─renren-generator 代码生成器 │ └─resources │ ├─mapper MyBatis文件 │ ├─template 代码生成器模板(可增加或修相应模板) │ ├─application.yml 全局配置文件 │ └─generator.properties 代码生成器,配置文件 │ ├─renren-ui 美食元素后台管理Vue前端项目 ├─takeout_mp uniapp微信小程序项目 ``` ## 项目特点 - 友好的代码结构及注释,便于阅读及二次开发 - 实现前后端分离,通过token进行数据交互 - 支持动态权限修,采用RBAC模型,前端菜单和后台权限实时更新。 - 提供CrudService接口,对增删查进行封装,代码更简洁 - 页面交互使用Vue2.x,极大的提高了开发效率 - 完善的部门管理及数据权限,通过注解实现数据权限的控制 - 完善的XSS防范及脚本过滤,彻底杜绝XSS攻击 - 完善的代码生成机制,可在线生成entity、xml、dao、service、vue、sql代码,减少70%以上的开发任务 - 引入quartz定时任务,可动态完成任务的添加、修、删除、暂停、恢复及日志查看等功能 - 引入Hibernate Validator校验框架,轻松实现后端校验 - 引入云存储服务,已支持:七牛云、阿里云、腾讯云等 - 引入swagger文档支持,方便编写API接口文档 - 新增AOP注解实现日志管理。 - 代码遵循阿里巴巴开发规范,利于开发者学习。 ## 技术选型 - 核心框架:Spring Boot 2.7.1 - 安全框架:Apache Shiro 1.9 - 持久层框架:MyBatis 3.5 - 定时器:Quartz 2.3 - 数据库连接池:Druid 1.2 - 日志管理:Logback - 页面交互Vue2.x - 微信小程序:uni-app ## 开发环境 | 开发工具 | 说明 | | ----------------------------- | ------------------ | | IDEA | Java开发工具IDE | | WebStrom或者VS Code | Vue开发工具IDE | | Navicat | MySQL远程连接工具 | | Another Redis Desktop Manager | R
VueSpringBoot实现项目前后端分离
weixin_69218754的博客
05-07 1534
VueSpringBoot实现项目前后端分离
前后端分离交互
m0_62565675的博客
12-14 6588
前言现在前端和后端已经完全分离,本篇文章会从javaEE环境的安装一直到会话跟踪结束,搭建一个学生管理系统的登录需求,实现前后端的基本交互
SpringBoot+Security+Vue前后端分离开发权限管理系统
04-10
适用人群所有的IT从业者,尤其适合快速掌握新技术,快速增长工作经验人群,对教育公平,教育公益,教育爱心公益人士课程概述该互联网实战项目是基于 Spring Boot 2+ SpringSecurity5+Element UI+Vue Admin Template+蚂蚁可视化AntV 等技术栈开发的项目,采用分布式,多模块,前后端分离开发。包括图形展示、权限管理、用户管理等功能。【后端技术】技术说明Spring Boot2MVC框架 开发的一站式解决方案Spring Security5 认证和授权框架MyBatisPlus3.3.1 基于 MyBatis 框架的快速研发框架MyBatisCode工具生成 MyBatis 相关代码Jackson提供了处理 JSON 数据的工具Lombok简化对象封装工具 Druid   数据库连接池 【前端技术】Vue       互联网最火的前端框架Vue Router路由框架Vuex全局状态管理框架Axios前端 HTTP 框架Element UI前端 UI 框架Vue Element Admin前端模板Antv  蚂蚁金服可视化技术,阿里巴巴可视化技术,天猫,淘宝,支付宝,花呗均使用AntV【开发工具】IntelliJ IDEA开发 IDESQLyog数据库连接客户端PostmanHTTP 请求工具【开发环境】工具版本JDK1.8MySQL5.7
前后端分离-小项目-3前后端交互
stein的博客
02-16 838
ajax 表单 crud 分页 带检索
前后端交互流程
weixin_71243923的博客
10-19 1万+
前后端交互流程
vue+springboot前后端分离交互(快速上手)
lj20020302的博客
03-15 3133
vue+springboot的快速开始入门操作,我是跟着视频一步一步来的,然后看完之后尝试着总结一个,希望可以帮助到正在迷茫的同行们。有什么题可以私信我,大家共同进步!
基于SpringBoot+vue+mysql前后端分离的社区维修平台源码+文档.zip
07-22
该系统的前端部分采用了Vue框架进行开发,主要实现了用户界面和交互,包括登录、注册、发布维修信息、查询维修信息、订单管理等功能。而后端部分则采用了SpringBoot框架,负责处理用户请求、管理用户数据并提供相应...
基于SpringBoot+Vue前后端分离的电影系统源码(毕业设计).zip
最新发布
04-03
前端源码:基于 Vue 框架实现的电影系统的前端代码,包括页面设计、交互逻辑、数据展示等部分。 这个项目是一个毕业设计,采用了前后端分离的架构,通过 Spring Boot 后端和 Vue 前端技术,实现了一个电影信息管理...
本科毕业设计+基于SpringBoot+Vue构建的中小企业进销存管理系统
06-20
实现前后端分离,通过token进行数据交互前端再也不用关注后端技术 支持结合ELK实时日志分析系统,方便日志查询,题排查,上线检查 灵活的权限控制,可控制到页面和按钮,满足绝大部分的权限需求 可在线生成vue、...
基于SpringBoot+vue+Vue的常规应急物资管理系统(源码+部署说明+演示视频+源码介绍).rar
03-10
这是一款基于SpringBoot+Vue的常规应急物资管理系统,旨在帮助企业和组织更有效地管理和调度应急物资。系统提供了丰富的功能,包括物资入库、出库、库存查询、物资分类管理、供应商管理等,以满足不同场景下的物资...
基于SpringBoot+vue+vue的游戏交易系统(源码+部署说明+演示视频+源码介绍).rar
03-10
该系统采用了流行的前后端分离架构,后端使用SpringBoot进行开发,负责处理业务逻辑和数据存储;前端使用Vue进行开发,负责展示用户界面和与后端进行交互。 系统功能主要包括:用户注册与登录、游戏商品上架、购买...
基于SpringBoot+Vue的信息技术知识赛系统的设计与实现(源码+部署说明+演示视频+源码介绍).zip
03-09
通过Ajax与后端进行数据交互实现了题目展示、答题记录、成绩统计等功能。 此外,系统还提供了丰富的题库资源,涵盖了计算机基础知识、编程语言、网络技术等多个领域。用户可以根据自己的需求,选择合适的题目进行...
基于SpringBoot+vueJava web的药店管理系统的设计与实现(源码+部署说明+演示视频+源码介绍).zip
03-10
在技术实现上,前端使用了Vue.js框架,通过Ajax与后端进行数据交互。后端使用了SpringBoot框架,通过JPA进行数据库操作。系统的数据存储使用了MySQL数据库。 源码包含了完整的前端和后端代码,以及数据库脚本。部署...
springboot+vue实现前后端分离具体框架代码
09-14
### 回答1: 可以使用 Spring Boot + Vue + Webpack 来实现前后端分离的框架,具体代码如下:Spring Boot:<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>Vue:<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>Webpack:const path = require('path'); const webpack = require('webpack');module.exports = { entry: './src/js/app.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'bundle.js' }, plugins: [ new webpack.ProvidePlugin({ $: 'jquery', jQuery: 'jquery' }) ] }; ### 回答2: 要实现Spring BootVue前后端分离,可以使用以下具体的框架和代码: 1. 后端使用Spring Boot框架实现RESTful API: - 创建一个Spring Boot项目,添加所需的依赖(如Spring Web、Spring Data JPA等)。 - 在项目中创建一个Controller类,使用`@RestController`注解标记。 - 编写各个API接口对应的方法,并使用`@RequestMapping`等注解进行路由映射。 - 可以使用Spring Data JPA来简化数据库操作,创建实体类和对应的Repository接口。 - 通过`@CrossOrigin`注解允许跨域请求。 2. 前端使用Vue框架实现单页应用: - 创建一个Vue项目,可以使用Vue CLI工具进行脚手架搭建。 - 在项目中创建相应的组件,用于展示数据和处理用户交互。 - 使用Vue Router进行前端路由管理。 - 使用Axios库进行前后端数据交互,发送HTTP请求获取后端API返回的数据。 - 使用Vue的生命周期钩子函数和Vue数据绑定特性来处理页面逻辑。 3. 连接前后端: - 在Vue的组件中使用Axios发送请求到后端API。 - 接收后端返回的数据,并在页面上进行展示。 - 在触发某些事件时,调用Axios发送请求到后端API来更新数据。 这样,就可以实现前后端分离的架构。后端通过Spring Boot框架提供RESTful API,前端使用Vue框架构建单页应用,并通过Axios库发送HTTP请求和后端进行数据交互。通过这种方式,前后端可以独立开发和部署,提高了开发效率和灵活性。 ### 回答3: 要实现Spring BootVue前后端分离,可以采用以下具体的框架和代码实现。 1. 后端框架:Spring Boot Spring Boot是一种用于构建独立的、基于Spring的Java应用程序的框架。它可以简化Spring应用程序的配置和部署,并提供了可集成的开发和测试工具。使用Spring Boot可以快速搭建后端API服务。 2. 前端框架:Vue.js Vue.js是一种用于构建用户界面的JavaScript框架,它可以实现响应式的数据绑定和组件化的开发。Vue.js使用简洁的语法和强大的生态系统,使得前端开发更加高效和可维护。 3. 框架整合 在实现前后端分离的过程中,可以通过Restful API进行前后端数据交互。后端使用Spring Boot提供API接口,前端使用Vue.js发起HTTP请求获取数据。 典型的框架代码结构如下: - 后端代码结构 - src/main/java - com.example.demo - controller - UserController.java:定义用户相关的API接口,处理HTTP请求。 - model - User.java:定义用户类,包含用户的属性和方法。 - service - UserService.java:定义用户相关的业务逻辑,如用户的增删查。 - UserServiceImpl.java:实现UserService接口的具体逻辑。 - repository - UserRepository.java:定义用户数据的访方式,如数据库操作。 - src/main/resources - application.properties:配置Spring Boot应用的相关属性。 - 前端代码结构 - src - components - UserList.vue:用户列表组件,展示后端返回的用户数据。 - views - User.vue:用户界面,包含用户的增删查等操作。 - router - index.js:前端路由配置文件,定义前端路由和页面的映射关系。 - App.vue:根组件,包含整个前端应用的布局和共享逻辑。 - main.js:入口文件,初始化Vue应用。 以上是一个简单的示例,可以根据实际需求和复杂程度进行相应的调整。通过Spring Boot提供API接口,Vue.js发起HTTP请求获取数据实现前后端分离的开发模式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
写文章

热门文章

  • Springboot+Vue实现简单的前端后分离数据交互 54190
  • Idea热加载插件JRebel激活及使用教程 30325
  • MyBatis-Plus代码生成器(新)使用 24232
  • SpringBoot集成JWT实现Token登录验证 11610
  • MySQL存储过程的使用实现数据快速插入 9599

分类专栏

  • 服务器与运维 7篇
  • SpringBoot 23篇
  • springcloud 10篇
  • vue 4篇
  • 数据库 13篇
  • Java 9篇
  • ssm整合 1篇
  • Git 1篇
  • 设计模式 2篇

最新评论

  • SpringBoot集成JWT实现Token登录验证

    深情不及里子: 取决于前端你设置的什么名称

  • SpringBoot集成JWT实现Token登录验证

    weixin_74879390:   为什么有的添加拦截器获取的请求头是authorization而有些是token啊?

  • 关于这款开源的ES的ORM框架-Easy-Es适合初学者入手不?

    深情不及里子: 需要技术非纯开发的:测试,技术支持,实施,运维,DBA,网络安全; 不需要技术的:售前,客户成功,业务项目经理,需求分析,ui ,产品,解决方案,项目助理

  • 关于这款开源的ES的ORM框架-Easy-Es适合初学者入手不?

    MO慕雨: 好奇转啥行业了,我也菜,感觉活不下去了,又不知道转啥

  • 关于这款开源的ES的ORM框架-Easy-Es适合初学者入手不?

    深情不及里子: 算是吧,太卷,个人技术也比较菜,现在只能算业余爱好了表情包

您愿意向朋友推荐“博客详情页”吗?

  • 强烈不推荐
  • 不推荐
  • 一般般
  • 推荐
  • 强烈推荐
提交

最新文章

  • Docker-Compose进行容器编排的简单使用
  • Windows Server2019上安装CentOS7流程梳理
  • Spring中事务传播机制的理解与简单试用
2023年25篇
2022年23篇
2021年6篇

目录

目录

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

深圳SEO优化公司桂林百度网站优化林芝建站来宾设计公司网站推荐镇江网站改版报价塘坑阿里店铺运营哪家好拉萨网站推广方案哪家好怒江模板网站建设开封百度标王公司平湖外贸网站建设南阳营销型网站建设报价吴忠外贸网站制作报价四平阿里店铺运营价格甘南网站优化按天收费报价温州关键词按天计费价格安阳百度seo报价潍坊网站排名优化推荐绍兴seo优化价格黔西南设计网站公司阜新建网站价格清远百度竞价哪家好本溪网站优化按天扣费梧州高端网站设计多少钱大庆seo桐城外贸网站设计推荐昌吉如何制作网站报价梧州营销网站多少钱绥化品牌网站设计哪家好宣城网络营销多少钱鹤岗网站搜索优化龙岗外贸网站设计报价歼20紧急升空逼退外机英媒称团队夜以继日筹划王妃复出草木蔓发 春山在望成都发生巨响 当地回应60岁老人炒菠菜未焯水致肾病恶化男子涉嫌走私被判11年却一天牢没坐劳斯莱斯右转逼停直行车网传落水者说“没让你救”系谣言广东通报13岁男孩性侵女童不予立案贵州小伙回应在美国卖三蹦子火了淀粉肠小王子日销售额涨超10倍有个姐真把千机伞做出来了近3万元金手镯仅含足金十克呼北高速交通事故已致14人死亡杨洋拄拐现身医院国产伟哥去年销售近13亿男子给前妻转账 现任妻子起诉要回新基金只募集到26元还是员工自购男孩疑遭霸凌 家长讨说法被踢出群充个话费竟沦为间接洗钱工具新的一天从800个哈欠开始单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#中国投资客涌入日本东京买房两大学生合买彩票中奖一人不认账新加坡主帅:唯一目标击败中国队月嫂回应掌掴婴儿是在赶虫子19岁小伙救下5人后溺亡 多方发声清明节放假3天调休1天张家界的山上“长”满了韩国人?开封王婆为何火了主播靠辱骂母亲走红被批捕封号代拍被何赛飞拿着魔杖追着打阿根廷将发行1万与2万面值的纸币库克现身上海为江西彩礼“减负”的“试婚人”因自嘲式简历走红的教授更新简介殡仪馆花卉高于市场价3倍还重复用网友称在豆瓣酱里吃出老鼠头315晚会后胖东来又人满为患了网友建议重庆地铁不准乘客携带菜筐特朗普谈“凯特王妃P图照”罗斯否认插足凯特王妃婚姻青海通报栏杆断裂小学生跌落住进ICU恒大被罚41.75亿到底怎么缴湖南一县政协主席疑涉刑案被控制茶百道就改标签日期致歉王树国3次鞠躬告别西交大师生张立群任西安交通大学校长杨倩无缘巴黎奥运

深圳SEO优化公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化