Spring Boot+Vue从零开始搭建系统(三):项目先后端分离_实现简单登陆demo

前言

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


DEMO功能描述

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


DEMO技术栈描述

1.前端技术栈:前端

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

2.后端技术栈:vue

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

DEMO开发流程概要

1.前端开发流程html5

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

2.后端开发流程java

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

3.运行项目流程node

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

4.开发过程当中注意点webpack

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

DEMO开发流程详情

前端开发内容

结构预览

图片描述

安装nodejs并初始化Vue项目

查看文章http://www.noobyard.com/article/p-tngbbycm-kh.html,按步骤操做便可。
使用axios前先执行cd W:\Workspaces\git_repositories\javalsj-blog-vue进入Vue项目目录下,执行命令cnpm install axios安装axios。ios


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

BlogHeader.vue 页面头代码:git

<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协议,可参考文章http://www.noobyard.com/article/p-ppilxtla-ez.html


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

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

前端代码打包

执行 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功能来演示前端开发、后端开发、先后端分离的完整集成和运行的过程,实际开发中比这会复杂的多,此文仅做了解流程使用。
图片描述