【从零开始做码农-vue+springboot+axios】

一切的开始

如何成为一个码农,这是一个问题。
一般来说,要想成为一名程序员,首先要做的第一件事就是选择。人的精力是有限的,没有多少人可以在多个方向同时取得巨大的成就。当然,大佬除外。而对于我们这些凡人老说,想要将事情做好就得确认自己的方向,这便是选择。
选择基本决定了将来的方向,比如人们常说的搞c++会秃头,搞java会减寿等等。很少有人能在决定了方向之后又重新选择另一条道路,这要求人能有足够的勇气跳出自己的舒适区去谋求未知的未来。这对于我等凡人来说实在有些困难。
所以,对于大多数人来说,选择很重要。对于那些不想要踏入java苦海的人来说,看到这里就足够了。

vue+springboot

java是一门十分流行的语言,是这个世界上使用人数最多的程序语言之一。这让java的拓展库十分强大。而这么庞大的拓展库让java的开发变得便利,大大减少了实现一个功能的时间。但同时,也让java程序的编写变得更加的重复化和规则化。使用java来实现功能不再是挠头苦想该怎么去实现一个功能,而变成了遇到问题就上网搜为什么会报错。
于此同时,java的学习也变得不仅仅是学习java语言本身。就现在的环境而言,光是会java却对于其他拓展库一窍不通还是很难找到工作的。java的学习某种意义上已经开始和各种拓展库挂钩。
在这里,本次的项目会使用vue+springboot作为最核心的拓展库。

开发工具

idea。

新手应该在这之前做的事

1.安装jdk。
步骤:https://www.runoob.com/java/java-environment-setup.html
2.安装node。
步骤:https://www.runoob.com/nodejs/nodejs-install-setup.html
3.安装mysql。
步骤:https://www.runoob.com/mysql/mysql-install.html
4.安装vue-cli。
步骤:https://cli.vuejs.org/zh/guide/installation.html

创建前端项目

进入cmd。(windows键+r,输入cmd,回车)
通过cmd命令跳转到目标位置,即你所想要前端项目在的那个位置。
输入vue create hello-world执行。

遇到选择默认回车。创建项目完成后,idea打开该项目。

点击下方的terminal,输入npm run serve然后执行。
打开一个浏览器,地址处输入localhost:8080回车。

可以看到页面上出现了这样一个样式。值得庆贺,一切的工作已经完成了一半(然而并不是)。

创建后端项目

idea点击file-new-project新建项目
在这里插入图片描述
next
在这里插入图片描述
将包名、项目名等按照自己的意思改一改,然后继续next
在这里插入图片描述
springboot集成了很多quickStart,免去了很多加依赖的功夫,在创建项目的时候就可以在这里加上。
继续next。
在这里插入图片描述
选择路径。finish!
在这里插入图片描述
后端项目创建完成。值得庆贺,vue+springboot已经创建完成了!(然而并不是)

配置maven

在真正开始写代码之前,我们还有一些工作需要做。
第一个便是配置maven。
idea点击file-settings
在这里插入图片描述
然后在搜索框输入maven,找到maven配置页面。
虽然说idea自己集成了maven,但是这在很多时候并不适合我们的需求。比如进入了公司后不同的项目组有着不同的maven设置,甚至于连接的地址也不尽相同。
又或者说公司使用的maven版本并不是3.6.1之类的。
总而言之,让我们自己搞一个maven来用。
首先这是地址:maven
在这里插入图片描述
进入网站后下拉到最下,找到Maven Releases History,点击右边的archives,去下载历史版本。当然,如果想用最新版也可以直接点击下载。
在这里插入图片描述
点击3.6.1-binaries/-apache-maven-3.6.1-bin.zip 下载
下载完成后将压缩文件解压到适合的位置。
随后,可以进入解压缩的maven文件夹下,打开conf文件夹,再打开setting文件。(提一句,setting文件这种xml文件可以试着用notepad++打开,很方便的一款小软件。)

<mirros></mirros>

中间加上

<mirror> 
    <id>nexus-aliyun</id> 
     <mirrorOf>central</mirrorOf>
    <name>Nexus aliyun</name> 
    <url>http://maven.aliyun.com/nexus/content/groups/public</url>
    </mirror>

这是干啥的呢?看名字就知道,这是阿里云,很多依赖连接国外的网站下载速度会很慢,连接国内的阿里云就会快很多。
除此之外,还可以ctrl+f搜索一下localRepository。

<localRepository>e:/project/maven/repository</localRepository>

修改一下,或者已经被注释了的也可以新加一个。
这个地址按照自己的需求来修改。
那么这又是干啥的呢?
这就是maven的仓库,那些下载下来的依赖当然不会放在桌面上,这个地址便是依赖存放的位置。
maven配置改得差不多了,可以和我们的项目勾上了。
回到idea项目。
在这里插入图片描述
配置maven。ok~!

数据库

看起来,我们的准备已经很完善了。(然而并不是)
作为一个完整的项目,我们需要持久化的数据。我们需要一个数据库来存放我们项目的数据!
所以让我干吧。
选择mysql作为我们的数据库。
作为一名合格的码农,我们必须要学会偷懒。不会偷懒的码农是不合格的。
在遇到一个问题的第一瞬间,我们的脑海里应该想的是,有没有什么偷懒的办法。
所以理所当然的,如果让我自己去create table,insert into什么的我自然是不愿意的。有偷懒的方法我为什么不用?当然,也会有人认为自己去写sql有利于稳固知识。放心,对于真正进入工作的同学们来说,很多时候crud能写到你想吐。现在咱们就先偷偷懒吧。
nvicat,毫无疑问是个好软件。Navicat Premium也是个好软件。我们往往只需要简单的百度一下,就能够找到学习的资源。嗯,网络真是个好东西。
简而言之,打开我们的nvicat!
在这里插入图片描述
点击:连接-mysql
连接上后就可以在左侧栏位看到该连接。
点进去,右键新建一个数据库。
然后再紧跟着新建一张表。
在这里插入图片描述
我们的数据库就这么简单的搭建好了。
在这里插入图片描述
id可以设置为自动递增,可以省去一些功夫。

后端配置

搞到现在,可能会有些人问:教练,咱们可以开始写代码了吗?
代码这种事情没必要忙。
其实某种意义上来说代码才是java里面最简单的内容。毕竟大量重复的操作会让你的代码越来越熟练,写个一年半载的之后,闭着眼睛写代码都不成问题。
然而项目的搭建,配置的修改之类的玩意。由于实际工作中使用的频率很低,反而会更容易出错。
更何况实际进入了工作之后,轮到你搭建项目的机会也不多。咱们自己搞的时候多熟悉熟悉也不是坏事。
首先,咱们搭建出来的后端项目应该是这样的:
在这里插入图片描述
找到application.properties
然后把它改为.yml。yml文件格式和properties文件格式有一些区别。但都不影响配置。只不过yml文件格式感觉起来更好用一些。
加上配置。
在这里插入图片描述

server:
  port: 8088
spring:
  datasource:
    name: test
    url: jdbc:mysql://127.0.0.1:3306/test?serverTimezone=GMT%2B8&useSSL=FALSE
    username: root
    password: 123456
mybatis:
  mapper-locations: classpath:mapper/*.xml

server既是服务,port是端口,这项配置的意思是我们这个项目服务的端口是8088,要访问的话记得朝着端口发消息。
spring既是spring框架,datasource代表数据来源,即数据库。name不需要解释,url是访问数据库的路径。
其中jdbc:mysql://127.0.0.1:3306是访问的地址,/test是表示要访问的数据库名。即我们刚刚创建的那个数据库。?后的内容则是这个访问的配置。
mybatis配置,mapper-locations的配置是mapper的位置。
classpath相当于application.yml本身所在的路径,mapper/*.xml则表示了配置文件同级目录的mapper文件夹下以xml为文件名后缀的文件。
所以我们的mapper文件也就应该放在这个位置,直接新建一个mapper文件夹。
在这里插入图片描述

前端代码编写

接下来,我们要给前端加‘依赖’了!
作为一名程序员,往往在遇到问题的第一瞬间,要想一想有没有其他人已经有了解决这个问题的方案。那么自己就不用再复杂地重复了。
当然,作为一名码农,我们肯定不会自己去费时费力地写什么button、table之类的html和css。
能用已有的为什么还要自己写?
所以说让我们引入element-ui,额,或者ant-design-vue。
不得不说的是,作为两个都很好用的前端框架,两者都是不错的选择。国内似乎element-ui的知名度要更高一些。但是个人而言,感觉ant-design-vue好像好用一点点。比如说在form组件上,ant-design有个label-col,wrapper-col可以用于调整form-item的显示比例。
只不过,ant-design-vue只支持vue3.0。现在的话,使用2.0的情况可能要多一些。
所以,咱们在这里还是先使用element-ui。

安装element-ui。
https://element.eleme.cn/#/zh-CN/component/installation

在terminal中执行npm i element-ui -S
然后在main.js中加上

import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';

Vue.use(ElementUI);

就这么简单,element-ui的已经安装完毕。

接下来,我们继续加‘依赖’。
Axios。
Axios 是一个基于 promise 的 HTTP 库。它的作用很简单,就是和后端交流。
毕竟我们的前端项目和后端项目是两个项目,两者直接并没有直接的联系,想要将两个项目联系起来自然需要交流的方法。而http方法就是我们web开发的最合适的方法。
而axios,则是将我们的http集成为了一个可用性很高的组件。使用axios完全可以省去大量的http的操作。
在terminal中执行npm install axios。
在main.js中加上如下。

import Axios from "axios";

Vue.prototype.$axios = Axios
Axios.defaults.baseURL = '/api'

Axios的使用过程中存在着一个问题,跨域。
什么是跨域?
浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域。
而我们的前端项目和后端项目显然不可能注册在同一个端口。所以自然而然的存在着跨域。
跨域会导致什么?
1、无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB
2、无法接触非同源网页的 DOM
3、无法向非同源地址发送 AJAX 请求(可以发送,但浏览器会拒绝接受响应)
因此,我们的axios的post请求或者get请求都会被拒绝响应。
那么,如何解决跨域问题?
实际上有很多方法,比如修改header为允许所有来源访问,允许post、get访问的方式,又或者修改请求的地址。
就比如我们现在使用的。

Axios.defaults.baseURL = '/api'

在axios请求上增加baseURL:‘/api’。
然后在前端根目录增加一个配置文件:vue.config.js。
在这里插入图片描述

module.exports = {
    devServer: {
        proxy: {
            '/api': {
                // 此处的写法,目的是为了 将 /api 替换成 http://localhost:8088
                target: 'http://localhost:8088',
                secure: false,  // 如果是https接口,需要配置这个参数
                // 允许跨域
                changeOrigin: true,
                ws: true,//是否代理websockets
                pathRewrite: {
                    '^/api': ''
                }
            }
        }
    }
}

这样,就会在在本地会创建一个虚拟服务端,然后发送请求的数据,并同时接收请求的数据,这样服务端和服务端进行数据的交互就不会有跨域问题。

‘依赖’的配置到此基本告一段落,接下来就是快乐的代码时间了。

首先,将原有的vue代码删去。
加上data、methods。
在这里插入图片描述
data,在vue的api文档中说明如下:

Vue 实例的数据对象。Vue 会递归地把 data 的 property 转换为 getter/setter,从而让 data 的 property 能够响应数据变化。对象必须是纯粹的对象 (含有零个或多个的 key/value 对):浏览器 API 创建的原生对象,原型上的 property 会被忽略。大概来说,data 应该只能是数据 - 不推荐观察拥有状态行为的对象。

一旦观察过,你就无法在根数据对象上添加响应式 property。因此推荐在创建实例之前,就声明所有的根级响应式 property。

实例创建之后,可以通过vm.$data 访问原始数据对象。Vue 实例也代理了 data 对象上所有的 property,因此访问 vm.a 等价于访问 vm.$data.a。

以 _ 或 $ 开头的 property 不会被 Vue 实例代理,因为它们可能和 Vue 内置的 property、API 方法冲突。你可以使用例如 vm.$data._property 的方式访问这些 property。

当一个组件被定义,data 必须声明为返回一个初始数据对象的函数,因为组件可能被用来创建多个实例。如果 data 仍然是一个纯粹的对象,则所有的实例将共享引用同一个数据对象!通过提供 data 函数,每次创建一个新实例后,我们能够调用 data 函数,从而返回初始数据的一个全新副本数据对象。

如果需要,可以通过将 vm.$data 传入 JSON.parse(JSON.stringify(…)) 得到深拷贝的原始数据对象。

以上内容看起来或许有些复杂,但是简单来说的话,就是data里面最好就是放一些数据,data下面的数据可以直接被vue实例调用,因为它递归地给这些数据对象生成了getter和setter。
至于组件,可以看做是java里面的接口,又或者c++里的多继承,父类里面的数据就相当于组件里data声明的数据。只不过这个数据是静态数据,多个继承类里会调用到同一个数据。而要应对这一问题,就需要将data里的数据对象设定为一个函数。就好比我们所使用的data(){return{}}。这样的话每一个调用组件的实例都会调用函数生成一个新的对象,这个静态数据也就变为了非静态。
如果是java基础不好的同学,也不需要太在意这些问题,可以在之后有时间慢慢研究。(毕竟在实际工作中基本都是一样的写法。)

继续,接下来是methods。
methods就是普通的存放函数的位置,在methods中声明的methods能够通过vue实例直接访问。
也就是说,如果注册了一个组件,也就相当于声明一个类,那么可以通过这个组件的实例,或者说相当于这个类的实例,直接调用这个组件里的函数,或者说相当于类里的函数。
是不是感觉有些异曲同工之妙?实际上很多语言基本都是有着大致相同的设计思想,只要学会了一门编程语言,学起其他的语言起来也会显得事半功倍。
然后用element-ui加上一些简单的前端功能。
首先是一个form。
在这里插入图片描述
form是一个经常用到重要组件,很多功能都会用到form。主要是用于将数据提交。当然,这都是按照需求而言。具体使用还需要按照实际的情况而定。
在script中,也要相应的加上对应的data和method。
在这里插入图片描述
formData与form中绑定的对应。submitData方法则使用axios将formData中的数据传递到后端。
resetForm则将form表单中填入的数据进行清空。
formData不需要太多解释,数据都是这类的写法。
axios方法则需要解释一二。
首先,在此前main.js中,我们加上了一行代码:

Vue.prototype.$axios = Axios

这行代码的意义,将Axios赋值到vue实例的属性中,命名为$axios。
这样我们就可以在vue的实例中直接使用Axios。

submitData () {
      let data = this.formData    // 将data数据写入变量
      this.$axios({             // 调用axios方法发动http请求
        method: 'post',      // 访问方式 post
        url: '/user/insertBaseUser',     // 访问路径 
        data              // 访问数据
      }).then(()=>{
        this.formData = {}     // 访问结束后清空formData中的数据
        this.resetForm('form')    // 清空表单数据
      })
    },
    resetForm (formName) {  // element-ui提供的清空表单方法
      this.$refs[formName].resetFields();   
    }

除了新增数据,我们至少也应该讲数据展示出来,让我们可以看到新增数据是否成功。
所以我们加上一个table。

    <el-form :model="searchFormData" inline ref="searchForm" label-width="80px">
      <el-form-item label="用户名">
        <el-input v-model="searchFormData.username"></el-input>
      </el-form-item>
      <el-form-item>
        <el-button @click="searchData">查询</el-button>
      </el-form-item>
    </el-form>
    <el-table
            :data="tableData"
            style="width: 100%">
      <el-table-column
              prop="name"
              label="姓名"
              width="180">
      </el-table-column>
      <el-table-column
              prop="username"
              label="用户名"
              width="180">
      </el-table-column>
      <el-table-column
              prop="coin"
              label="积分">
      </el-table-column>
    </el-table>

前一个searchForm是将查询的条件捕捉起来。绑定了searchFormData,与之前的新增相似。
而table则是按照element的格式使用,绑定数据tableData。
在script方面,为searchFormData和tableData声明好数据格式:
在这里插入图片描述
随后加上click点击事件的响应函数,往后端发送请求。

    searchData () {
      let data = this.searchFormData
      this.$axios({
        method: 'post',
        url: '/user/queryBaseUser',
        data
      }).then(res=>{
        this.tableData = res.data
      })
    },

promise接受到后端传回的数据,将其赋值到tableData即可。
到此,前端已经实现了一个最基础的功能,可以去将后端的相应支持也实现了。

后端代码编写

后端的代码编写,按照分层的格式进行编写。
在这里插入图片描述
首先在application文件的同层创建controller、service、dao、dto等文件夹。
这是springMVC的分层设计。具体的可以下去自己搜索了解。
这里首先在dto文件夹创建一个BaseUserDTO文件。
在这里插入图片描述
在这个文件中,我们要将数据库的数据结构等效搬到java这里。此外,还需要为这个类增加对应private元素增加相应的getter和setter。在这里使用lombok给省略掉了。
要使用lombok的话,就需要在pom文件中加上相应的依赖。

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.18</version>
            <scope>provided</scope>
        </dependency>

接下来,在resource的mapper文件夹中创建mapper.xml:BaseUserMapper。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<!--上面2行的是约束依赖,固定照抄就好-->
<!--下面的才是要自己编写的地方-->
<!--写mapper的配置文件第一步就是要写<mapper></mapper>标签-->
<!--<mapper></mapper>标签里包含着各个CURD操作的SQL语句-->
<mapper namespace="com.xychen.helloback.dao.BaseUserMapper">
    <!--定义一个名为BaseResultMap的返回类型-->
    <resultMap id="BaseResultMap" type="com.xychen.helloback.dto.BaseUserDTO">
        <id column="id" property="id" jdbcType="INTEGER"></id>
        <result column="name" property="name" jdbcType="VARCHAR"></result>
        <result column="username" property="username" jdbcType="VARCHAR"></result>
        <result column="password" property="password" jdbcType="VARCHAR"></result>
        <result column="coin" property="coin" jdbcType="INTEGER"></result>
    </resultMap>

    <!--插入语句-->
    <!--id要与UserMapper文件中表示插入的函数名一致,parameterType表示函数的输入参数的类型-->
    <insert id="insertBaseUser" parameterType="com.xychen.helloback.dto.BaseUserDTO">
        insert into base_user(id,name,username,password,coin)
        values (#{id,jdbcType=INTEGER},
                #{name,jdbcType=VARCHAR},
                #{username,jdbcType=VARCHAR},
                #{password,jdbcType=VARCHAR},
                #{coin,jdbcType=INTEGER})
    </insert>

    <!--查找语句-->
    <!--resultMap表示函数返回的类型-->
    <select id="selectUser" parameterType="com.xychen.helloback.dto.BaseUserDTO" resultMap="BaseResultMap">
       select * from base_user where
       1 = 1
       <if test="id != null and id != 0">
            and id = #{id,jdbcType=INTEGER}
       </if>
        <if test="name != null and name != ''">
            and name = #{name,jdbcType=VARCHAR}
        </if>
        <if test="username != null and username != ''">
            and username = #{username,jdbcType=VARCHAR}
        </if>
        <if test="password != null and password != ''">
            and password = #{password,jdbcType=VARCHAR}
        </if>
    </select>

</mapper>

mapper中查询sql是mybatis的动态sql,根据入参的不同来改变sql的条件。这里的where 1=1 也可以替换为:

<where>
</where>

mapper.xml文件创建完毕后,在java的dao文件夹中创建dao,BaseUserMapper。与之前的xml文件同名。

@Mapper
public interface BaseUserMapper {
    int insertBaseUser(BaseUserDTO baseUserDTO);

    List<BaseUserDTO> selectUser(BaseUserDTO baseUserDTO);
}

使用@mapper注释。
随后在service文件夹下创建service接口和其实现类。
service接口:

public interface BaseUserService {
    public int insertBaseUser(BaseUserDTO baseUserDTO);
    public List<BaseUserDTO> queryBaseUser(BaseUserDTO baseUserDTO);
}

service实现类:

@Service("BaseUserService")
public class BaseUserServiceImpl implements BaseUserService {

    @Autowired
    private BaseUserMapper baseUserDAO;

    @Override
    public int insertBaseUser(BaseUserDTO baseUserDTO) {
        return baseUserDAO.insertBaseUser(baseUserDTO);
    }

    @Override
    public List<BaseUserDTO> queryBaseUser(BaseUserDTO baseUserDTO) {
        return baseUserDAO.selectUser(baseUserDTO);
    }
}

使用service注释,将service名也写入。使用autowired将dao引入使用。
随后便是在controller文件夹下创建controller文件。

@RestController
@RequestMapping("/user")
public class BaseUserController {

    @Autowired
    private BaseUserService baseUserService;

    @RequestMapping("/insertBaseUser")
    public int insertBaseUser(@RequestBody BaseUserDTO baseUserDTO) {
        int i = baseUserService.insertBaseUser(baseUserDTO);
        return i;
    }

    @RequestMapping("/queryBaseUser")
    public List<BaseUserDTO> queryBaseUser(@RequestBody BaseUserDTO baseUserDTO) {
        List<BaseUserDTO> baseUserDTOS = baseUserService.queryBaseUser(baseUserDTO);
        return baseUserDTOS;
    }

}

运行项目

至此,项目实现了基本的功能。
将两个项目都启动起来试一试。
在这里插入图片描述
可以看到结果还是能用的,具体到真实的项目中可能会复杂一些,前端也需要优化,但总体基础都是类似的。所以到这里为止,至少我们已经掌握了一个码农所需要的一些基础知识。往后也是继续添砖加瓦便是。

  • 4
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
实现列拖拽功能可以使用 SortableJS 库,并结合 Element Plus 的表格组件和 Vue3 的响应式数据。 首先需要在项目中安装 SortableJS: ``` npm install sortablejs --save ``` 然后在需要使用的组件中引入 SortableJS 和 Element Plus 的表格组件: ```javascript import Sortable from 'sortablejs'; import { ElTable, ElTableColumn } from 'element-plus'; ``` 接着,在组件中定义表格数据和表格列,以及拖拽回调函数: ```javascript export default { data() { return { tableData: [ { name: 'John', age: 20, address: 'New York' }, { name: 'Tom', age: 25, address: 'London' }, { name: 'Lucy', age: 18, address: 'Paris' }, { name: 'Lily', age: 22, address: 'Tokyo' } ], tableColumns: [ { label: 'Name', prop: 'name' }, { label: 'Age', prop: 'age' }, { label: 'Address', prop: 'address' } ] }; }, mounted() { // 绑定拖拽回调函数 const el = this.$refs.table.$el.querySelector('.el-table__body-wrapper tbody'); Sortable.create(el, { animation: 150, onEnd: evt => { const { newIndex, oldIndex } = evt; const item = this.tableColumns.splice(oldIndex - 1, 1)[0]; this.tableColumns.splice(newIndex - 1, 0, item); } }); }, render() { return ( <ElTable ref="table" data={this.tableData}> {this.tableColumns.map(column => ( <ElTableColumn label={column.label} prop={column.prop}></ElTableColumn> ))} </ElTable> ); } }; ``` 这里使用 `Sortable.create` 方法创建一个拖拽对象,并且绑定了 `onEnd` 回调函数,当拖拽结束后,将表格列数组中的相应元素移动到新位置。 最后渲染表格时,使用 `map` 方法动态创建表格列。 这样就实现了列拖拽功能。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值