前言

本文主要是想通过后端 Spring Boot 技术和前端 Vue 技术来简单开发一个登录demo,该demo以简单、方便理解的方式来记录前后端结合使用的过程,方便正式开发复杂项目时能提前整体理解流程,demo最终实现的效果如下图:


DEMO功能描述

输入http://localhost:8080回车浏览器自动跳转到http://localhost:8080/login登录页面,登录页面包含页面头部、登录信息页面、页面尾部。输入用户名、密码点击登录功能实现效果如下:
1.输入服务器不正确的用户名密码,如输入用户名wangjihong登录,会在登录验证情况文本框中显示后端端验证后的错误信息。
2.输入正确的用户名密码,如输入用户名javalsj密码123456登录,则服务端验证正确后前端页面自动跳转到首页http://localhost:8080/index。


DEMO技术栈描述

1.前端技术栈:

.编程语言:html5、js、css
.开发工具:Visual Studio Code
.开发框架:vue + axios
.包管理工具:npm
.打包工具:webpack

2.后端技术栈:

.编程语言:java
.开发工具:Eclipse
.开发框架:spring boot
.包管理工具:gradle构建工具下的maven资源库
.打包工具:gradle

DEMO开发流程概要

1.前端开发流程

.安装nodejs并初始化Vue项目。
.在已初始化的Vue项目中的开发页面头、页面尾公共组件。
.开发登录页面组件。
.开发首页页面组件。
.支持跨域,请求路由,页面路由开发。
.单独运行Vue项目查看效果。

2.后端开发流程

.安装JDK10并配置好JAVA_HOME环境变量.
.初始化springboot项目。
.开发restful控制器。
.支持跨域。
.单独运行后端springboot项目查看效果。

3.运行项目流程

.使用webpack将Vue项目打包。
.将打包的Vue项目集成到springboot项目中。
.使用gradle将springboot打包成jar文件。
.使用jdk运行jar包来启动demo项目服务,请访问地址查看效果。

4.开发过程中注意点

.前端项目由于启用了eslint语法检测,所以有时候多个空格或者少个空格或者少个空行,都会运行不起来前端项目,对应提示信息改下即可。
.前端发送请求的数据格式需要与后端接收请求数据对象格式要约定一致。
.在前后端未集成的时候需要跨域支持。

DEMO开发流程详情

前端开发内容

结构预览

图片描述

安装nodejs并初始化Vue项目

查看文章https://segmentfault.com/a/1190000013950461,按步骤操作即可。
使用axios前先执行cd W:\Workspaces\git_repositories\javalsj-blog-vue进入Vue项目目录下,执行命令cnpm install axios安装axios。


在已初始化的Vue项目中的开发页面头、页面尾公共组件

BlogHeader.vue 页面头代码:

<template>
    <div>
        页面头部
    </div>
</template>

<script>
export default {
  name: 'BlogHeader'
}
</script>

BlogFooter.vue 页面尾部代码:

<template>
    <div>
        页面尾部
    </div>
</template>

<script>
export default {
  name: 'BlogFooter'
}
</script>

开发登录页面组件

BlogLogin.vue 登录页面代码:

<template>
  <div>
    <blog-header></blog-header>
    <hr/>
    <div>
      用户名:<input type="text" v-model="loginInfoVo.username" placeholder="请输入用户名" />
      <br/>
      密码:<input type="password" v-model="loginInfoVo.password" placeholder="请输入密码" />
      <br/>
      <button v-on:click="login">登录</button>
      <br/>
      登录验证情况:<textarea cols="30" rows="10" v-model="responseResult"></textarea>
    </div>
    <hr/>
    <blog-footer></blog-footer>
  </div>
</template>

<script>
import blogHeader from '@/components/common/BlogHeader.vue'
import blogFooter from '@/components/common/BlogFooter.vue'

export default {
  name: 'BlogLogin',
  // blogHeader、blogFooter组件给申明到components里面然后在template里面使用
  components: { blogHeader, blogFooter },
  data () {
    return {
      loginInfoVo: { username: '', password: '' },
      responseResult: []
    }
  },
  methods: {
    login () {
      this.$axios
        .post('/login', {
          username: this.loginInfoVo.username,
          password: this.loginInfoVo.password
        })
        .then(successResponse => {
          this.responseResult = JSON.stringify(successResponse.data)
          if (successResponse.data.code === 200) {
            this.$router.replace({path: '/index'})
          }
        })
        .catch(failResponse => {})
    }
  }
}
</script>

开发首页页面组件

BlogIndex.vue 首页页面代码:

<template>
  <div>
    <blog-header></blog-header>
    <hr/>
    <div>
      这是首页,嘻嘻嘻。
    </div>
    <hr/>
    <blog-footer></blog-footer>
  </div>
</template>

<script>
import blogHeader from '@/components/common/BlogHeader.vue'
import blogFooter from '@/components/common/BlogFooter.vue'

export default {
  name: 'BlogIndex',
  // blogHeader/blogFooter组件给申明到components里面然后在template里面使用
  components: { blogHeader, blogFooter }
}
</script>

支持跨域,请求路由,页面路由开发

main.js 主入口代码:

import Vue from 'vue'
import App from './App'
import router from './router'
// 引用axios,并设置基础URL为后端服务api地址
var axios = require('axios')
axios.defaults.baseURL = 'https://localhost:8443/api'
// 将API方法绑定到全局
Vue.prototype.$axios = axios
Vue.config.productionTip = false

/* eslint-disable */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

router/index.js 页面路由代码:

import Vue from 'vue'
import Router from 'vue-router'
import BlogLogin from '@/components/manage/BlogLogin.vue'
import BlogIndex from '@/components/home/BlogIndex.vue'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      redirect: '/login'
    },
    {
      path: '/index',
      name: 'BlogIndex',
      component: BlogIndex
    },
    {
      path: '/manage',
      redirect: '/login'
    },
    {
      path: '/login',
      name: 'BlogLogin',
      component: BlogLogin
    }
  ]
})

config/index.js 跨域支持代码:
找到文件中的proxyTable位置修改为以下内容添加请求到后端的跨域支持。

// 路由接口代理配置
proxyTable: {
  '/api': {
    target: 'https://localhost:8443',
    changeOrigin: true,
    pathRewrite: {
        '^/api': ''
    }
  }
}

单独运行Vue项目查看效果

访问地址:http://localhost:8080看效果如下:
图片描述


后端开发内容

结构预览

图片描述

安装JDK10并配置好JAVA_HOME环境变量

这里不介绍,网上搜一下相关文档。

初始化SpringBoot项目

这里也不做介绍,网上搜一下相关文档。。

开发登录控制器

1.开发请求映射对象代码
VueLoginInfoVo.java :

package com.javalsj.blog.pojo.vo;

import javax.validation.constraints.NotNull;

/** 
 * @description Vue登录页面demo信息对象实体
 * @author WANGJIHONG
 * @date 2018年4月5日 下午10:57:53 
 * @Copyright 版权所有 (c) www.javalsj.com
 * @memo 备注信息
 */
public class VueLoginInfoVo {
    
    @NotNull(message="用户名不允许为空")
    private String username;
    
    @NotNull(message="密码不允许为空")
    private String password;

    public String getUsername() {
        return username;
    }

    public String getPassword() {
        return password;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }

}

2.开发响应结果对象代码
Result.java:

package com.javalsj.blog.result;

/**
 * @description 统一 API响应结果封装
 * @author WANGJIHONG
 * @date 2018年3月13日 下午8:44:29
 * @Copyright 版权所有 (c) www.javalsj.com
 * @memo 控制Result权限,构建结果Result对象统一使用com.javalsj.blog.vo.ResultFactory工厂类来创建
 */
public class Result {
    /**
     * 响应状态码
     */
    private int code;
    /**
     * 响应提示信息
     */
    private String message;
    /**
     * 响应结果对象
     */
    private Object data;

    Result(int code, String message, Object data) {
        this.code = code;
        this.message = message;
        this.data = data;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

}

ResultCode:

package com.javalsj.blog.result;

/**
 * @description 响应码枚举,参考 HTTP状态码的语义
 * @author WANGJIHONG
 * @date 2018年3月13日 下午8:35:00
 * @Copyright 版权所有 (c) www.javalsj.com
 * @memo 无备注说明
 */
public enum ResultCode {
    /** 
     * 成功
     */ 
    SUCCESS(200),
    /** 
     * 失败 
     */ 
    FAIL(400),
    
    /** 
     * 未认证(签名错误)
     */ 
    UNAUTHORIZED(401),
    
    /** 
     * 接口不存在
     */ 
    NOT_FOUND(404),
    
    /** 
     * 服务器内部错误
     */ 
    INTERNAL_SERVER_ERROR(500);

    public int code;

    ResultCode(int code) {
        this.code = code;
    }
    
}

ResultFactory:

package com.javalsj.blog.result;

/**
 * @description 响应结果生成工厂类
 * @author WANGJIHONG
 * @date 2018年3月13日 下午8:36:58
 * @Copyright 版权所有 (c) www.javalsj.com
 * @memo 无备注说明
 */
public class ResultFactory {

    public static Result buildSuccessResult(Object data) {
        return buidResult(ResultCode.SUCCESS, "成功", data);
    }

    public static Result buildFailResult(String message) {
        return buidResult(ResultCode.FAIL, message, null);
    }

    public static Result buidResult(ResultCode resultCode, String message, Object data) {
        return buidResult(resultCode.code, message, data);
    }
    
    public static Result buidResult(int resultCode, String message, Object data) {
        return new Result(resultCode, message, data);
    }
}

3.开发登录控制器,支持跨域。
LoginController 代码:

import javax.validation.Valid;

import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.javalsj.blog.pojo.vo.VueLoginInfoVo;
import com.javalsj.blog.result.Result;
import com.javalsj.blog.result.ResultFactory;

@Controller
public class LoginController {

    /**
     * 登录控制器,前后端分离用的不同协议和端口,所以需要加入@CrossOrigin支持跨域。
     * 给VueLoginInfoVo对象加入@Valid注解,并在参数中加入BindingResult来获取错误信息。
     * 在逻辑处理中我们判断BindingResult知否含有错误信息,如果有错误信息,则直接返回错误信息。
     */
    @CrossOrigin
    @RequestMapping(value = "/api/login", method = RequestMethod.POST, produces = "application/json; charset=UTF-8")
    @ResponseBody
    public Result login(@Valid @RequestBody VueLoginInfoVo loginInfoVo, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            String message = String.format("登陆失败,详细信息[%s]。", bindingResult.getFieldError().getDefaultMessage());
            return ResultFactory.buildFailResult(message);
        }
        if (!Objects.equals("javalsj", loginInfoVo.getUsername()) || !Objects.equals("123456", loginInfoVo.getPassword())) {
            String message = String.format("登陆失败,详细信息[用户名、密码信息不正确]。");
            return ResultFactory.buildFailResult(message);
        }
        return ResultFactory.buildSuccessResult("登陆成功。");
    }


}

4.单独运行后端springboot项目
此处忽略,配置服务端口为8443,支持https协议,可参考文章https://segmentfault.com/a/1190000013777395


集成前后端代码,运行完整项目流程

前端服务启动、后端服务启动,然后操作按前言的演示图片内容操作即可,下面进行前后端代码集成操作。

前端代码打包

执行 cd W:\Workspaces\git_repositories\javalsj-blog-vue 进入项目目录下,执行 npm run build命令进行打包,会自动生成打包后的dist目录文件。如图:
图片描述


前端代码集成到springboot项目中

把dist里面所有文件都拷贝到springboot项目的resources/static目录下,如下图:
图片描述
然后重启springboot项目,浏览器访问后台服务地址:https://localhost:8443,会发现页面显示的就是vue开发的前端页面,然后输入用户名密码登录正常。
图片描述
图片描述
通过上面步骤集成前后端完毕,然后把完整的项目打包成jar包后使用jdk命令运行完整项目即可。


总结

本文主要以一个简单的登录demo功能来演示前端开发、后端开发、前后端分离的完整集成和运行的过程,实际开发中比这会复杂的多,此文仅作了解流程使用。
图片描述

Logo

前往低代码交流专区

更多推荐