vue+iview+springboot全栈开发

基本配置
1.安装WebStorm。

2.安装NodeJS。
Node.js 安装配置

3.设置阿里镜像服务。
vue+iview+springboot全栈开发_第1张图片4.安装vue-cli组件。
命令行输入:npm install -g vue-cli

5.安装GIT客户端环境。
安装之后需要配置->高级系统设置->环境变量->系统变量->Path->新建->C:\Program Files\Git\bin

------------------------------------------------------------------------------------------------------------------------------

HelloWorld项目
项目写好之后,需要发布,发布的命令:
npm run build

注意dist目录下的index.html文件中的绝对路径和相对路径,应修改为:

myweb

即去掉static前面的"/"。将绝对路径改为相对路径。
或者修改config目录下的index.js文件中的build模块为:

  build: {
    // Template for index.html
    index: path.resolve(__dirname, '../dist/index.html'),

    // Paths
    assetsRoot: path.resolve(__dirname, '../dist'),
    assetsSubDirectory: 'static',
    assetsPublicPath: '',

即将assetsPublicPath设置为空。
最后重新发布。

运行结果:
vue+iview+springboot全栈开发_第2张图片

------------------------------------------------------------------------------------------------------------------------------

iview界面库
iView

使用 iview-loader 统一代码风格
View UI Loader

注意:要修改index.js文件中的

useEslint: false,

即:vue+iview+springboot全栈开发_第3张图片

在main.js中引入ViewUI:

import ViewUI from 'view-design'
import 'view-design/dist/styles/iview.css'

Vue.use(ViewUI)

在iview界面库中寻找代码替换App.vue中的代码:

<style scoped>
  .layout{
    border: 1px solid #d7dde4;
    background: #f5f7f9;
    position: relative;
    border-radius: 4px;
    overflow: hidden;
  }
  .layout-logo{
    width: 100px;
    height: 30px;
    background: #5b6270;
    border-radius: 3px;
    float: left;
    position: relative;
    top: 15px;
    left: 20px;
  }
  .layout-nav{
    width: 420px;
    margin: 0 auto;
    margin-right: 20px;
  }
</style>
<template>
  <div class="layout">
    <Layout>
      <Header>
        <Menu mode="horizontal" theme="dark" active-name="1">
          <div class="layout-logo"></div>
          <div class="layout-nav">
            <MenuItem name="1">
              <Icon type="ios-navigate"></Icon>
              Item 1
            </MenuItem>
            <MenuItem name="2">
              <Icon type="ios-keypad"></Icon>
              Item 2
            </MenuItem>
            <MenuItem name="3">
              <Icon type="ios-analytics"></Icon>
              Item 3
            </MenuItem>
            <MenuItem name="4">
              <Icon type="ios-paper"></Icon>
              Item 4
            </MenuItem>
          </div>
        </Menu>
      </Header>
      <Layout>
        <Sider hide-trigger :style="{background: '#fff'}">
          <Menu active-name="1-2" theme="light" width="auto" :open-names="['1']">
            <Submenu name="1">
              <template slot="title">
                <Icon type="ios-navigate"></Icon>
                Item 1
              </template>
              <MenuItem name="1-1">Option 1</MenuItem>
              <MenuItem name="1-2">Option 2</MenuItem>
              <MenuItem name="1-3">Option 3</MenuItem>
            </Submenu>
            <Submenu name="2">
              <template slot="title">
                <Icon type="ios-keypad"></Icon>
                Item 2
              </template>
              <MenuItem name="2-1">Option 1</MenuItem>
              <MenuItem name="2-2">Option 2</MenuItem>
            </Submenu>
            <Submenu name="3">
              <template slot="title">
                <Icon type="ios-analytics"></Icon>
                Item 3
              </template>
              <MenuItem name="3-1">Option 1</MenuItem>
              <MenuItem name="3-2">Option 2</MenuItem>
            </Submenu>
          </Menu>
        </Sider>
        <Layout :style="{padding: '0 24px 24px'}">
          <Breadcrumb :style="{margin: '24px 0'}">
            <BreadcrumbItem>Home</BreadcrumbItem>
            <BreadcrumbItem>Components</BreadcrumbItem>
            <BreadcrumbItem>Layout</BreadcrumbItem>
          </Breadcrumb>
          <Content :style="{padding: '24px', minHeight: '280px', background: '#fff'}">
            <div>
              Props:
              <Input prefix="ios-contact" placeholder="请输入姓名" style="width: auto" />
              <Input suffix="ios-search" placeholder="请输入内容" style="width: auto" />
              <Switch v-model="switch1" @on-change="change" />
              <Rate v-model="fenshu" />
            </div>
            <div style="margin-top: 6px">
              Slots:
              <Input placeholder="请输入姓名" style="width: auto">
                <Icon type="ios-contact" slot="prefix" />
              </Input>
              <Input placeholder="请输入内容" style="width: auto">
                <Icon type="ios-search" slot="suffix" />
              </Input>
            </div>
          </Content>
        </Layout>
      </Layout>
    </Layout>
  </div>
</template>
<script>
export default {
  data () {
    return {
      switch1: false,
      fenshu: 3
    }
  },
  methods: {
    change (status) {
      this.$Message.info('开关状态:' + status);
    }
  }
}
</script>

运行结果:
vue+iview+springboot全栈开发_第4张图片

------------------------------------------------------------------------------------------------------------------------------

后端开发环境(Eclipse+Springboot2)
vue+iview+springboot全栈开发_第5张图片

------------------------------------------------------------------------------------------------------------------------------

编写服务端REST数据接口
在pom.xml文件中引入依赖:

		
		
		    com.itshidu.web
		    web-tools
		    1.0
		

在Hello.java中添加代码:

package com.itshidu.demo.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.itshidu.web.tools.Result;

@RestController
public class Hello {
	
	@RequestMapping("/api/score")
	public Object score() {
		
		return Result.of(1).put("xixi", "西西"); // {code:1,"name":"西西"}
	}
}

------------------------------------------------------------------------------------------------------------------------------

使用 axios 进行AJAX功能开发
安装axios以及示例

------------------------------------------------------------------------------------------------------------------------------

用VUE跨域调用服务端的数据
在Hello.java中添加SpringBoot跨域注解:

package com.itshidu.demo.controller;

import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.itshidu.web.tools.Result;

@CrossOrigin(origins = "*") // SpringBoot跨域注解
@RestController
public class Hello {
	
	@RequestMapping("/api/score")
	public Object score() {
		
		return Result.of(1).put("xixi", "西西"); // {code:1,"name":"西西"}
	}
}

在main.js文件中添加代码:

import axios from 'axios'

Vue.prototype.axios = axios

在App.vue文件中添加代码:

export default {
  data () {
    return {
      switch1: false,
      fenshu: 3
    }
  },
  methods: {
    change (status) {
      this.$Message.info('开关状态:' + status)
    }
  },
  created () {
    var url = 'http://localhost:8390/api/score'
    this.axios.get(url).then(response => {
      this.fenshu = response.data.code
    })
  }
}

运行结果:
vue+iview+springboot全栈开发_第6张图片

------------------------------------------------------------------------------------------------------------------------------

自定义组件设置宽度为1200像素
在components目录下创建一个Vue组件,取名为:MyPanel,添加代码:

<template>
  <div class = "my-panel"><slot></slot></div>
</template>

<script>
/* 此组件用于设置宽度为1000px */
export default {
  name: 'MyPanel'
}
</script>

<style scoped>
.my-panel{
  width: 1000px;
  margin-right: auto;
  margin-left: auto;
}
</style>

------------------------------------------------------------------------------------------------------------------------------

路由组件
Vue Router

#作为路由的开始。

先来看一下router文件夹下的index.js文件(整个路由都在这里定义):

import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'HelloWorld',
      component: HelloWorld
    }
  ]
})

在App.vue中添加代码:

 <router-view></router-view>

如图:
vue+iview+springboot全栈开发_第7张图片
运行结果:vue+iview+springboot全栈开发_第8张图片

------------------------------------------------------------------------------------------------------------------------------

点击导航菜单然后路由到对应页面
在components目录下创建一个Index.vue组件,添加代码:

<style scoped>
  .layout{
    border: 1px solid #d7dde4;
    background: #f5f7f9;
    position: relative;
    border-radius: 4px;
    overflow: hidden;
  }
  .layout-logo{
    width: 100px;
    height: 30px;
    background: #5b6270;
    border-radius: 3px;
    float: left;
    position: relative;
    top: 15px;
    left: 20px;
  }
  .layout-nav{
    width: 420px;
    margin: 0 auto;
    margin-right: 20px;
  }
</style>
<template>
  <div class="layout">
    <Layout>
      <Header>
        <Menu mode="horizontal" theme="dark" active-name="1">
          <div class="layout-logo"></div>
          <div class="layout-nav">
            <MenuItem name="1">
              <Icon type="ios-navigate"></Icon>
              Item 1
            </MenuItem>
            <MenuItem name="2">
              <Icon type="ios-keypad"></Icon>
              Item 2
            </MenuItem>
            <MenuItem name="3">
              <Icon type="ios-analytics"></Icon>
              Item 3
            </MenuItem>
            <MenuItem name="4">
              <Icon type="ios-paper"></Icon>
              Item 4
            </MenuItem>
          </div>
        </Menu>
      </Header>
      <Layout>
        <Sider hide-trigger :style="{background: '#fff'}">
          <Menu active-name="1-2" theme="light" width="auto" :open-names="['1']">
            <Submenu name="1">
              <template slot="title">
                <Icon type="ios-navigate"></Icon>
                Item 1
              </template>
              <MenuItem name="1-1">Option 1</MenuItem>
              <MenuItem name="1-2">Option 2</MenuItem>
              <MenuItem name="1-3">Option 3</MenuItem>
            </Submenu>
            <Submenu name="2">
              <template slot="title">
                <Icon type="ios-keypad"></Icon>
                Item 2
              </template>
              <MenuItem name="2-1">Option 1</MenuItem>
              <MenuItem name="2-2">Option 2</MenuItem>
            </Submenu>
            <Submenu name="3">
              <template slot="title">
                <Icon type="ios-analytics"></Icon>
                Item 3
              </template>
              <MenuItem name="3-1">Option 1</MenuItem>
              <MenuItem name="3-2">Option 2</MenuItem>
            </Submenu>
          </Menu>
        </Sider>
        <Layout :style="{padding: '0 24px 24px'}">
          <Breadcrumb :style="{margin: '24px 0'}">
            <BreadcrumbItem>Home</BreadcrumbItem>
            <BreadcrumbItem>Components</BreadcrumbItem>
            <BreadcrumbItem>Layout</BreadcrumbItem>
          </Breadcrumb>
          <Content :style="{padding: '24px', minHeight: '280px', background: '#fff'}">
            <div>
              Props:
              <Input prefix="ios-contact" placeholder="请输入姓名" style="width: auto" />
              <Input suffix="ios-search" placeholder="请输入内容" style="width: auto" />
              <Switch v-model="switch1" @on-change="change" />
              <Rate v-model="fenshu" />
            </div>
            <div style="margin-top: 6px">
              Slots:
              <Input placeholder="请输入姓名" style="width: auto">
                <Icon type="ios-contact" slot="prefix" />
              </Input>
              <Input placeholder="请输入内容" style="width: auto">
                <Icon type="ios-search" slot="suffix" />
              </Input>
            </div>
          </Content>
        </Layout>
      </Layout>
    </Layout>
  </div>
</template>
<script>
export default {
  data () {
    return {
      switch1: false,
      fenshu: 3
    }
  },
  methods: {
    change (status) {
      this.$Message.info('开关状态:' + status)
    }
  },
  created () {
    var url = 'http://localhost:8390/api/score'
    this.axios.get(url).then(response => {
      this.fenshu = response.data.code
    })
  }
}
</script>

修改App.vue中的代码为:

<style scoped>

</style>
<template>
<router-view></router-view>
</template>
<script>
export default {

}
</script>

跳转方法一:修改Index.vue文件中的代码:

            <MenuItem name="1" @click.native="urlto">
              <Icon type="ios-navigate"></Icon>
              欢迎界面
            </MenuItem>
  methods: {
    change (status) {
      this.$Message.info('开关状态:' + status)
    },
    urlto () {
      this.$router.push('/hello')
    }
  },

运行结果:
vue+iview+springboot全栈开发_第9张图片
vue+iview+springboot全栈开发_第10张图片
跳转方法二:使用iView中的Menu导航菜单自身的事件(注意@on-select要写在

中)。
修改Index.vue文件中的代码:

<Menu active-name="1-2" theme="light" width="auto" :open-names="['1']" @on-select="selectMenu">
	   <Submenu name="1">
	   <template slot="title">
	   <Icon type="ios-navigate"></Icon>
	       点我
	   </template>
	   <MenuItem name="/hello" >我也是欢迎菜单</MenuItem>
	   <MenuItem name="1-2">Option 2</MenuItem>
       <MenuItem name="1-3">Option 3</MenuItem>
  methods: {
    change (status) {
      this.$Message.info('开关状态:' + status)
    },
    urlto () {
      this.$router.push('/hello')
    },
    selectMenu (name) {
      this.$router.push(name)
    }
  },

运行结果:
vue+iview+springboot全栈开发_第11张图片
vue+iview+springboot全栈开发_第12张图片
------------------------------------------------------------------------------------------------------------------------------

编写service脚本统一处理数据请求
在src目录下创建一个utils目录,创建一个service.js文件,添加代码:

/*
*数据服务接口
**/

import Vue from 'vue'
import axios from 'axios'

const star = function (calback) {
  axios.get('http://localhost:8390/api/score').then(response => {
    calback(response.data.code)
  })
}

export {
  star
}

修改Index.vue中的代码:

import {star} from '@/utils/service'
  created () {
    star(code => {
      this.fenshu = code
    })
  }

------------------------------------------------------------------------------------------------------------------------------

把获取名字的接口也放到service中
1.创建获取名字的接口

const getDemoName = function (value) {
  axios.get('http://localhost:8390/api/value').then(response => {
    value(response.data.name)
  })
}

2.映射接口

export {
  getDemoName
}

3.引用接口

import {getDemoName} from '@/utils/service'

4.使用

export default {
  data () {
    return {
      value: ''
    }
  },
  created () {
    getDemoName(value => {
      this.value = value
    })
  }
}
<Input prefix="ios-contact" placeholder="请输入姓名" v-model="value" style="width: auto" />

后台代码:

	@RequestMapping("/api/value")
	public Object value() {
		return Result.of().put("name", "西西");
	}

运行结果:
vue+iview+springboot全栈开发_第13张图片

------------------------------------------------------------------------------------------------------------------------------

提取Header组件
我们以后会开发很多页面,并且Header对于很多页面都是通用的,所以我们可以单独把Header提取出来。

在components目录下创建一个MyHeader.vue组件,添加代码:

<template>
  <Header>
    <MyPanel>
    <Menu mode="horizontal" theme="dark" active-name="1" @on-select="selectMenu">
      <div class="layout-logo"></div>
      <div class="layout-nav">
        <MenuItem name="1" @click.native="urlto">
          <Icon type="ios-navigate"></Icon>
          欢迎界面
        </MenuItem>
        <MenuItem name="/hello" >
          <Icon type="ios-keypad"></Icon>
          Item2
        </MenuItem>
        <MenuItem name="/about">
          <Icon type="ios-analytics"></Icon>
          关于
        </MenuItem>
        <MenuItem name="4">
          <Icon type="ios-paper"></Icon>
          Item 4
        </MenuItem>
      </div>
    </Menu>
    </MyPanel>
  </Header>
</template>

<script>
import MyPanel from '@/components/MyPanel'
export default {
  name: 'MyHeader',
  components: {MyPanel},
  methods: {
    selectMenu (name) {
      this.$router.push(name)
    },
    urlto () {
      this.$router.push('/hello')
    }}
}
</script>

<style scoped>
  .layout-logo{
    width: 100px;
    height: 30px;
    background: #5b6270;
    border-radius: 3px;
    float: left;
    position: relative;
    top: 15px;
    left: 20px;
  }
  .layout-nav{
    width: 420px;
    margin: 0 auto;
    margin-right: 20px;
  }
</style>

在其他组件中直接使用即可。

------------------------------------------------------------------------------------------------------------------------------

创建About视图
在components目录下创建一个About.vue组件,添加代码:

<template>
  <div>
    <MyHeader></MyHeader>
    <Circle :percent="80">
      <span class="demo-Circle-inner" style="font-size:24px">80%</span>
    </Circle>
    <Circle :percent="100" stroke-color="#5cb85c">
      <Icon type="ios-checkmark" size="60" style="color:#5cb85c"></Icon>
    </Circle>
    <Circle :percent="35" stroke-color="#ff5500">
          <span class="demo-Circle-inner">
              <Icon type="ios-close" size="50" style="color:#f39eff"></Icon>
          </span>
    </Circle>
  </div>
</template>

<script>
import MyHeader from '@/components/MyHeader'
export default {
  name: 'About',
  components: {MyHeader}
}
</script>

<style scoped>

</style>

在index.js文件中添加路由:

import About from '@/components/About'

export default new Router({
  routes: [
    {
      path: '/about',
      name: 'About',
      component: About
    }
  ]
})

运行结果:
vue+iview+springboot全栈开发_第14张图片

------------------------------------------------------------------------------------------------------------------------------

编写Layout组件简化页面结构
在components目录下创建一个MyLayout.vue组件,添加代码:

<style scoped>
  .layout{
    border: 1px solid #d7dde4;
    background: #f5f7f9;
    position: relative;
    border-radius: 4px;
    overflow: hidden;
  }

  .layout-footer-center{
    text-align: center;
  }

</style>
<template>
  <div class="layout">
    <Layout>
      <MyHeader></MyHeader>
      <Content :style="{padding: '0 50px'}" class="my-panel">
      <MyPanel>
          <slot></slot>
      </MyPanel>
      </Content>
      <Footer class="layout-footer-center">2011-2016 &copy; TalkingData</Footer>
    </Layout>

  </div>
</template>
<script>
  import MyHeader from '@/components/MyHeader'
  import MyPanel from '@/components/MyPanel'
  export default {
    components: {MyPanel, MyHeader}
  }
</script>

修改About.vue组件的代码:

<template>
  <div>
    <MyLayout>
    <Circle :percent="80">
      <span class="demo-Circle-inner" style="font-size:24px">80%</span>
    </Circle>
    <Circle :percent="100" stroke-color="#5cb85c">
      <Icon type="ios-checkmark" size="60" style="color:#5cb85c"></Icon>
    </Circle>
    <Circle :percent="35" stroke-color="#ff5500">
          <span class="demo-Circle-inner">
              <Icon type="ios-close" size="50" style="color:#f39eff"></Icon>
          </span>
    </Circle>
    </MyLayout>
  </div>
</template>

<script>
import MyHeader from '@/components/MyHeader'
import MyLayout from '@/components/MyLayout'
export default {
  name: 'About',
  components: {MyLayout, MyHeader}
}
</script>

<style scoped>

</style>

------------------------------------------------------------------------------------------------------------------------------

添加注册登录按钮以及相关的页面路由
修改MyHeader.vue组件中的代码:

<template>
  <Header>
    <MyPanel>
    <Menu mode="horizontal" theme="dark" active-name="1" @on-select="routerTo">
      <div class="layout-logo"></div>
      <div class="layout-nav">
        <MenuItem name=" " >
          <Button type="info" @click="routerTo('/login')">登录</Button>
          <Button type="success" @click="routerTo('/register')">注册</Button>
        </MenuItem>
        <MenuItem name="/hello" >
          <Icon type="ios-keypad"></Icon>
          Item2
        </MenuItem>
        <MenuItem name="/about">
          <Icon type="ios-analytics"></Icon>
          关于
        </MenuItem>
        <MenuItem name="4">
          <Icon type="ios-paper"></Icon>
          Item 4
        </MenuItem>
      </div>
    </Menu>
    </MyPanel>
  </Header>
</template>

<script>
import MyPanel from '@/components/MyPanel'
export default {
  name: 'MyHeader',
  components: {MyPanel},
  methods: {
    routerTo (name) {
      this.$router.push(name)
    }
  }
}
</script>

<style scoped>
  .layout-logo{
    width: 100px;
    height: 30px;
    background: #5b6270;
    border-radius: 3px;
    float: left;
    position: relative;
    top: 15px;
    left: 20px;
  }
  .layout-nav{
    width: 420px;
    margin: 0 auto;
    margin-right: 20px;
  }
</style>

在src下创建一个views视图目录,在其下创建一个Login.vue视图和Register.vue视图。
Login.vue代码:

<template>
<MyLayout>登录页面</MyLayout>
</template>

<script>
  import MyLayout from '@/components/MyLayout'
  export default {
    name: 'Login',
    components: {MyLayout}
  }
</script>

<style scoped>

</style>

Register.vue代码:

<template>
  <MyLayout>注册页面</MyLayout>
</template>

<script>
  import MyLayout from '@/components/MyLayout'
  export default {
    name: 'Register',
    components: {MyLayout}
  }
</script>

<style scoped>

</style>

在index.js中添加代码:

import Login from '@/views/Login'
import Register from '@/views/Register'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/login',
      name: Login,
      component: Login
    },
    {
      path: '/register',
      name: Register,
      component: Register
    }

  ]
})

运行结果:
vue+iview+springboot全栈开发_第15张图片
vue+iview+springboot全栈开发_第16张图片
vue+iview+springboot全栈开发_第17张图片

------------------------------------------------------------------------------------------------------------------------------

路由的懒加载
延迟加载

import HelloWorld from '@/components/HelloWorld'
import Login from '@/views/Login'
import Register from '@/views/Register'

换成

const HelloWorld = () => { import('@/components/HelloWorld') }
const Login = () => { import(/* webpackChunkName: "group-user" */ '@/views/Login') }
const Register = () => { import(/* webpackChunkName: "group-user" */ '@/views/Register') }

------------------------------------------------------------------------------------------------------------------------------

Vuex的安装及初始化创建
官方文档
1.安装:

npm install vuex --save

2.在main.js中引入Vuex:

import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  }
})
new Vue({
  store   //全局对象
})

------------------------------------------------------------------------------------------------------------------------------

Vuex的核心作用及代码演示
可以将main.js中的

  components: { App },
  template: '',

替换为

 render: h => h(App)

在Index.vue组件下添加代码:

  <Button type = "info" @click="add">点我加1</Button>
  <h1>当前数值:{{this.$store.state.count}}</h1>
  methods: {
    add () {
      this.$store.commit('increment')
    }
  },

运行结果:
vue+iview+springboot全栈开发_第18张图片
vue+iview+springboot全栈开发_第19张图片

------------------------------------------------------------------------------------------------------------------------------

Vuex中的action动作
action和mutation类似,不同的是,action提交的是mutation,而不是直接变更状态。而且action支持异步,mutation必须同步执行。
mutation是最基本的操作,类似增删改查,是对数据的直接操作,而action则代表了具体的业务流程。

在main.js中添加代码:

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    waitIncrement (context, n) {
      setTimeout(() => {
        for (var i = 0; i < n; i++) {
          context.commit('increment')
        }
      }, 2000)
    }

  }
})

修改Index.vue中代码:

    add () {
      //this.$store.commit('increment')
      this.$store.dispatch('waitIncrement', 6)
    }

运行结果:
vue+iview+springboot全栈开发_第20张图片vue+iview+springboot全栈开发_第21张图片

------------------------------------------------------------------------------------------------------------------------------

Vuex的项目结构及模块
项目结构
在src下创建一个store目录,创建一个index.js文件,添加代码:

import Vue from 'vue'
// Vuex状态管理
import Vuex from 'vuex'
Vue.use(Vuex)

export const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    waitIncrement (context, n) {
      setTimeout(() => {
        for (var i = 0; i < n; i++) {
          context.commit('increment')
        }
      }, 2000)
    }

  }
})

在main.js文件中引入store:

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
import ViewUI from 'view-design'
import 'view-design/dist/styles/iview.css'

import axios from 'axios'
import {store} from '@/store/index'

Vue.prototype.axios = axios

Vue.use(ViewUI)
Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  store,
  render: h => h(App)
})

------------------------------------------------------------------------------------------------------------------------------

Vuex的模块化代码编写
在store目录下创建一个modules目录,创建一个hello.js文件,添加代码:

export const hello = {
  state: { count: 0 },
  mutations: {
    inc (state) {
      state.count++
    }
  },

  getters: {
    doubleCount (state) {
      return state.count * 2
    }
  },
  actions: {
    helloIncrement ({ state, commit, rootState }) {
      alert(rootState.count)
      commit('inc')// 此处的mutation名称不能与主模块的mutation名称相同,否则会同时调用主模块的mutation
    }
  }
}

在主模块store目录下的index.js文件中添加代码:

export const store = new Vuex.Store({
  state: {
    count: 6
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    waitIncrement (context, n) {
      setTimeout(() => {
        for (var i = 0; i < n; i++) {
          context.commit('increment')
        }
      }, 2000)
    }
  },
  modules: {
    hello: hello
  }
})

在Index.vue文件中添加代码:

 <Button type = "info" @click="add">点我加1</Button>
 <h1>主模块数值:{{this.$store.state.count}}</h1>
 <h1>子模块数值:{{this.$store.state.hello.count}}</h1>
  methods: {
    add () {
      this.$store.dispatch('helloIncrement')
    }
  },

运行结果:
vue+iview+springboot全栈开发_第22张图片vue+iview+springboot全栈开发_第23张图片vue+iview+springboot全栈开发_第24张图片

------------------------------------------------------------------------------------------------------------------------------

SpringBoot中的HttpSession有跨域问题
服务器记不住你是谁

跨域,指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器施加的安全限制。

所谓同源是指:域名,协议,端口均相同,不明白没关系,举个栗子:

http://www.123.com/index.html 调用 http://www.123.com/server.php (非跨域)

http://www.123.com/index.html 调用 http://www.456.com/server.php (主域名不同:123/456,跨域)

http://abc.123.com/index.html 调用 http://def.123.com/server.php (子域名不同:abc/def,跨域)

http://www.123.com:8080/index.html 调用 http://www.123.com:8081/server.php (端口不同:8080/8081,跨域)

http://www.123.com/index.html 调用 https://www.123.com/server.php (协议不同:http/https,跨域)

请注意:localhost和127.0.0.1虽然都指向本机,但也属于跨域。

------------------------------------------------------------------------------------------------------------------------------

后端使用拦截器支持跨域
创建一个interceptor包,创建一个AccessInterceptor类,添加代码:

package com.itshidu.demo.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;

public class AccessInterceptor implements HandlerInterceptor {
	@Override
public boolean preHandle(HttpServletRequest request,
		HttpServletResponse response, Object object) throws Exception {
		
		//response.setCharacterEncoding("UTF-8");
		//response.setContentType("application/json; charset=utf-8");
		response.setHeader("Access-Control-Allow-Credentials","true");
		response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
		response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
		response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH");
	
		return true;
	}
}

写完interceptor之后它是不生效的,还需要配置一下。
创建一个config包,创一个MvcConfig类,添加代码:

package com.itshidu.demo.config;

import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import com.itshidu.demo.interceptor.AccessInterceptor;

public class MvcConfig implements WebMvcConfigurer {
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		registry.addInterceptor(new AccessInterceptor()).addPathPatterns("/**");// /**代表可以访问所有资源
		
	}

}

------------------------------------------------------------------------------------------------------------------------------

后端使用CrossOrigin注解支持跨域
在需要跨域的类或方法前添加注解:

@CrossOrigin(origins = "*")

------------------------------------------------------------------------------------------------------------------------------
前端发送ajax请求时携带cookie

axios.defaults.withCredentials=true; //每次ajax请求时携带cookie

------------------------------------------------------------------------------------------------------------------------------

后端+前端彻底解决会话跨域丢失问题
运行结果:
vue+iview+springboot全栈开发_第25张图片

------------------------------------------------------------------------------------------------------------------------------

登录功能的JS前端代码
在service.js文件中添加代码:

const login = (username, password, callback) => {
  let data = new FormData()
  data.append('username', username)
  data.append('password', password)

  axios.post('http://localhost:8390/api/login', data).then(res => {
    callback(res.data)
  })
}

在Login.vue中添加代码:

<template>
<MyLayout>
  <Card>
    <h1>用户登录</h1>
    <input v-model="username" placeholder="请输入用户名:" style="width: 300px">
    <input v-model="password" placeholder="请输入密码:" style="width: 300px">
    <Button type="info" @click="login">登录</Button>
  </Card>
</MyLayout>

</template>

<script>
import MyLayout from '@/components/MyLayout'
import {login} from '@/utils/service'
export default {
  name: 'Login',
  components: {MyLayout},
  data () {
    return {
      username: ' ',
      password: ' '
    }
  },
  methods: {
    login () {
      login(this.username, this.password, data => {
        console.log(data)
      })
    }

  }
}
</script>

<style scoped>

</style>

------------------------------------------------------------------------------------------------------------------------------

登录功能的Java后端代码
在Hello.java文件中添加代码:

	@RequestMapping("/api/login")
	public Object login(String username, String password) {
		System.out.println(username);
		System.out.println(password);
		if (username.equals("xixi") && password.equals(" 123")){
			return Result.of(100,"登陆成功");
		}
		return Result.of(101,"登陆失败");
	}

------------------------------------------------------------------------------------------------------------------------------

三种POST传值与接收的方法
axios.post发送的参数:
1.JSON类型:将会以Payload形式发送,服务端需要使用@RequestBody接收为Map,Content-Type:application/json
2.FormDate类型:则Content-Type:multipart/form-data,可以上传表单也可以上传文件,不会编码处理。
3.QueryString:则Content-Type:application/x-www-form-urlencoded,标准的表单提交,会编码处理。

------------------------------------------------------------------------------------------------------------------------------

使用QS组件进行QueryString的序列化与反序列化
这个插件可以进行JSON数据和查询字符串之间的转换,能够实现序列化和反序列化。

安装命令:

npm i qs --save

导入qs:

import qs from 'qs'

qs插件中的两个主要方法:

qs.parse()
qs.stringify()

qs.parse()是将URL解析成对象的形式
qs.stringify()是将对象序列化成URL的形式,以&进行拼接

修改login.vue中的代码为:

const login = (username, password, callback) => {
  let data = qs.stringify({
    username: username,
    password: password
  })
  axios.post('http://localhost:8390/api/login', data).then(res => {
    callback(res.data)
  })
}

------------------------------------------------------------------------------------------------------------------------------

Springboot中使用DataJPA框架
让Springboot连接mysql。
在pom.xml文件中引入依赖:

		<dependency>
		    <groupId>org.springframework.boot</groupId>
		    <artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
		   <groupId>mysql</groupId>
		   <artifactId>mysql-connector-java</artifactId>
		   <version>5.1.47</version>
		</dependency>

添加配置信息:
在application.yml文件中添加代码:

spring:
    datasource:
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://localhost:3306/me_db?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&serverTimezone=UTC
        username: root
        password: 123
    jpa:
        show-sql: true
        hibernate:
            ddl-auto: update
            dialect: org.hibernate.dialect.MySQL5Dialect

创建一个entity包,创建一个User类,添加代码:

package com.itshidu.demo.entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 * @Entity:对实体注释,任何Hibernate映射对象都要有这个注解。
 * @Table:声明此对象映射到数据库的数据表,通过它可以为实体指定表(talbe),目录(Catalog)和数据库(schema)的名字。该注释不是必须的,如果没有则系统使用默认值(实体的短类名)。
 **/

@Entity 
@Table(name="vue_user")  

public class User {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;//这两个注解表示Id主键自增
	private String username;
	private String password;
	private String nickname;
	private int age;
	
	public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getNickname() {
		return nickname;
	}
	public void setNickname(String nickname) {
		this.nickname = nickname;
	}
		
}

运行结果:
vue+iview+springboot全栈开发_第26张图片

------------------------------------------------------------------------------------------------------------------------------

使用Lombok让代码更优雅
Lombok能以简单的注解形式来简化java代码,提高开发人员的开发效率。
例如开发中经常需要写的javabean,都需要花时间去添加相应的getter/setter,也许还要去写构造器、equals等方法,而且需要维护,当属性多时会出现大量的getter/setter方法,这些显得很冗长也没有太多技术含量,一旦修改属性,就容易出现忘记修改对应方法的失误。

Lombok能通过注解的方式,在编译时自动为属性生成构造器、getter/setter、equals、hashcode、toString方法。神奇的是在源码中没有getter和setter方法,但是在编译生成的字节码文件中有getter和setter方法。这样就省去了手动重建这些代码的麻烦,使代码看起来更简洁些。

@Data注解在类上,会为类的所有属性自动生成setter/getter、equals、canEqual、hashCode、toString方法,如为final属性,则不会为该属性生成setter方法。

如果觉得@Data太过残暴(因为@Data集合了@ToString、@EqualsAndHashCode、@Getter/@Setter、@RequiredArgsConstructor的所有特性)不够精细,可以使用@Getter/@Setter注解,此注解在属性上,可以为相应的属性自动生成Getter/Setter方法。

在pom.xml文件中添加依赖:

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

找到lombok.jar文件,双击安装。
注意可能遇到eclipse无法打开的问题,或者注解无效的问题,在eclipse.ini文件中添加代码即可解决:

-Xbootclasspath/a:lombok.jar  
-vmargs -javaagent:lombok.jar
-javaagent:lombok.jar

修改User实体类中的代码为:

package com.itshidu.demo.entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import lombok.Data;

/**
 * @Entity:对实体注释,任何Hibernate映射对象都要有这个注解。
 * @Table:声明此对象映射到数据库的数据表,通过它可以为实体指定表(talbe),目录(Catalog)和数据库(schema)的名字。该注释不是必须的,如果没有则系统使用默认值(实体的短类名)。
 * @Data:注解在类上,会为类的所有属性自动生成setter/getter、equals、canEqual、hashCode、toString方法,如为final属性,则不会为该属性生成setter方法。
 **/

@Data
@Entity 
@Table(name="vue_user")  
public class User {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;//这两个注解表示Id主键自增
	private String username;
	private String password;
	private String nickname;
	private int age;
		
}

更多关于lombok的使用参考这里

------------------------------------------------------------------------------------------------------------------------------

使用DataJPA实现真正的登录查询
创建一个dao包,创建一个UserDao接口(所有的JPAdao都会被自动加载),添加代码:

package com.itshidu.demo.dao;

import org.springframework.data.jpa.repository.JpaRepository;

import com.itshidu.demo.entity.User;

public interface UserDao extends JpaRepository<User, Long>{
	User findByUsername(String username);
}

在数据表中添加数据:
vue+iview+springboot全栈开发_第27张图片

在Hello.java中添加代码:

	@Autowired UserDao userDao;

修改登录方法为:

	@RequestMapping("/api/login")
	public Object login(String username, String password) {
		User user = userDao.findByUsername(username);
		if (user == null) {
			return Result.of(102, "用户不存在");
		}
		
		if (!user.getPassword().equals(password)) {
			return Result.of(103, "密码不正确");
		}
		return Result.of(100, "登录成功");
	}

修改前端中Login.vue中的代码为:

  methods: {
    login () {
      login(this.username, this.password, data => {
        console.log(data)
        if (data.code == 100) {
          this.$Message.success('登录成功')
        } else {
          this.$Message.warning(data.msg)
        }
      })
    }

  }

运行结果:
vue+iview+springboot全栈开发_第28张图片
vue+iview+springboot全栈开发_第29张图片
vue+iview+springboot全栈开发_第30张图片
------------------------------------------------------------------------------------------------------------------------------

服务端和客户端存储登录信息
在User实体类中的password属性上添加注解(密码不会传输到浏览器上):

	@JsonIgnore
	private String password;

修改Hello.java中的登录方法:

	@RequestMapping("/api/login")
	public Object login(String username, String password,HttpSession session) {
		User user = userDao.findByUsername(username);
		if (user == null) {
			return Result.of(102, "用户不存在");
		}
		
		if (!user.getPassword().equals(password)) {
			return Result.of(103, "密码不正确");
		}
		session.setAttribute("loginUser", user);
		return Result.of(100, "登录成功").put("user", user);
	}

修改login.vue中的代码:

  methods: {
    login () {
      login(this.username, this.password, data => {
        console.log(data)
        if (data.code === 100) {
          this.$Message.success('登录成功')
          this.$Message.success(data.user.nickname)
          window.sessionStorage.setItem('user', JSON.stringify(data.user))
        } else {
          this.$Message.warning(data.msg)
        }
      })
    }

  }

------------------------------------------------------------------------------------------------------------------------------

使用VUEX处理全局用户信息
在store目录下的index.js文件中添加代码:

  state: {
    count: 6,
    user: JSON.parse(window.sessionStorage.getItem('user'))
  },
  mutations: {
    setUser (state, user) {
      state.user = user
    },

在Login.vue中添加代码:

	this.$store.commit('setUser', data.user)

在MyHeader.vue中添加代码:

        <MenuItem name=" " v-if="this.$store.state.user==null">
          <Button type="info" @click="routerTo('/login')">登录</Button>
          <Button type="success" @click="routerTo('/register')">注册</Button>
        </MenuItem>
        <Submenu name="" v-if="this.$store.state.user!=null">
          <template slot="title">
            <Icon type="ios-person" />
            {{this.$store.state.user.nickname}}
          </template>
          <MenuGroup title="使用">
            <MenuItem name="3-1">个人中心</MenuItem>
            <MenuItem name="3-2">注销</MenuItem>
          </MenuGroup>
        </Submenu>

------------------------------------------------------------------------------------------------------------------------------

给路由跳转加上进度条
在main.js文件中添加代码:

import ViewUI from 'view-design';
Vue.use(ViewUI);

router.beforeEach((to, from, next) => {
    ViewUI.LoadingBar.start();
    next();
});

router.afterEach(route => {
    ViewUI.LoadingBar.finish();
});

------------------------------------------------------------------------------------------------------------------------------

实现用户注销功能
修改MyHeader.vue中的代码为:

<MenuItem name="" @click.native="logout">注销</MenuItem>

import {logout} from '@/utils/service'

  methods: {
    logout () {
      logout(data => {
        console.log(data)
        if (data.code === 100) {
          window.sessionStorage.clear()// 客户端数据清理
          this.$store.commit('setUser', null)// vuex数据清理
        }
      })
    }
 }

在service.js文件中添加代码:

const logout = (callback) => {
  axios.get('http://localhost:8390/api/logout').then(res => {
    callback(res.data)
  })
}


export {
  logout
}

在Hello.java文件中添加方法:

	@RequestMapping("/api/logout")
	public Object logout(HttpSession session) {
		session.invalidate();	//废弃当前session
		return Result.of(100, "注销成功");//服务端数据清理
	}

------------------------------------------------------------------------------------------------------------------------------

换一个漂亮一些的登录页面
安装:less-loader

npm install less-loader --save -dev

安装:less

npm install less --save -dev

在assets目录下创建一个images目录,放入login-bg.jpg图片。

在view目录下创建一个login文件夹。
创建一个login.vue文件,添加代码:

<style lang="less">
  @import './login.less';
</style>

<template>
  <div class="login">
    <div class="login-con">
      <Card icon="log-in" title="欢迎登录" :bordered="false">
        <div class="form-con">
          <login-form @on-success-valid="handleSubmit"></login-form>
          <p class="login-tip">输入任意用户名和密码即可</p>
        </div>
      </Card>
    </div>
  </div>
</template>

<script>
import LoginForm from '@/components/login-form'
import { mapActions } from 'vuex'
export default {
  components: {
    LoginForm
  },
  methods: {
    ...mapActions([
      'handleLogin',
      'getUserInfo'
    ]),
    handleSubmit ({ userName, password }) {
      this.handleLogin({ userName, password }).then(res => {
        this.getUserInfo().then(res => {
          this.$router.push({
            name: this.$config.homeName
          })
        })
      })
    }
  }
}
</script>

<style>

</style>

创建一个login.less文件,添加代码:

.login{
    width: 100%;
    height: 100%;
    background-image: url('../../assets/images/login-bg.jpg');
    background-size: cover;
    background-position: center;
    position: relative;
    &-con{
        position: absolute;
        right: 160px;
        top: 50%;
        transform: translateY(-60%);
        width: 300px;
        &-header{
            font-size: 16px;
            font-weight: 300;
            text-align: center;
            padding: 30px 0;
        }
        .form-con{
            padding: 10px 0 0;
        }
        .login-tip{
            font-size: 10px;
            text-align: center;
            color: #c3c3c3;
        }
    }
}
html,body{
  height: 100%;
}

在components目录下创建一个login-form.vue文件,添加代码:

<template>
  <Form ref="loginForm" :model="form" :rules="rules" @keydown.enter.native="handleSubmit">
    <FormItem prop="userName">
      <Input v-model="form.userName" placeholder="请输入用户名">
        <span slot="prepend">
          <Icon :size="16" type="ios-person"></Icon>
        </span>
      </Input>
    </FormItem>
    <FormItem prop="password">
      <Input type="password" v-model="form.password" placeholder="请输入密码">
        <span slot="prepend">
          <Icon :size="14" type="md-lock"></Icon>
        </span>
      </Input>
    </FormItem>
    <FormItem>
      <Button @click="handleSubmit" type="primary" long>登录</Button>
    </FormItem>
  </Form>
</template>
<script>
export default {
  name: 'LoginForm',
  props: {
    userNameRules: {
      type: Array,
      default: () => {
        return [
          { required: true, message: '账号不能为空', trigger: 'blur' }
        ]
      }
    },
    passwordRules: {
      type: Array,
      default: () => {
        return [
          { required: true, message: '密码不能为空', trigger: 'blur' }
        ]
      }
    }
  },
  data () {
    return {
      form: {
        userName: 'super_admin',
        password: ''
      }
    }
  },
  computed: {
    rules () {
      return {
        userName: this.userNameRules,
        password: this.passwordRules
      }
    }
  },
  methods: {
    handleSubmit () {
      this.$refs.loginForm.validate((valid) => {
        if (valid) {
          this.$emit('on-success-valid', {
            userName: this.form.userName,
            password: this.form.password
          })
        }
      })
    }
  }
}
</script>

修改router目录中的index.js文件(修改路由):

import Login from '@/views/login/login'

------------------------------------------------------------------------------------------------------------------------------

记住我7天功能
下载vue-cookies:

npm install vue-cookies --save

在login-form.vue文件中添加代码:

    <form-item>
      记住我7<Switch v-model='switchValue' @on-change="changes"></Switch>
    </form-item>


  data () {
    return {
      form: {
        userName: 'super_admin',
        password: '',
        switchValue: false
      }
    }
  },


  methods: {
    handleSubmit () {
      this.$refs.loginForm.validate((valid) => {
        if (valid) {
          this.$emit('on-success-valid', {
            userName: this.form.userName,
            password: this.form.password,
            rememberMe: this.switchValue
          })
        }
      })
    },
    changes (status) {
      this.$Message.info('开关状态' + status)
    }
  }

在main.js中添加代码(beforeEach之前):

import VueCookies from 'vue-cookies'

import {login} from '@/utils/service'
Vue.use(VueCookies)
Vue.use(ViewUI)

if (!store.state.user) {
  let rememberMe = VueCookies.get('rememberMe')
  if (rememberMe) {
    // 利用这个登录信息去登录
    login(rememberMe.username, rememberMe.password, data => {
      if (data.code === 100) {
        ViewUI.Message.success('自动登录成功')
        window.sessionStorage.setItem('user', JSON.stringify(data.user))
        store.commit('setUer', data.user)
      } else {
        ViewUI.Message.warning('自动登录结果' + data.msg)
      }
    })
  }
}

在login.vue中添加代码:

<style lang="less">
  @import './login.less';
</style>

<template>
  <div class="login">
    <div class="login-con">
      <Card icon="log-in" title="欢迎登录" :bordered="false">
        <div class="form-con">
          <login-form @on-success-valid="handleSubmit"></login-form>
          <p class="login-tip">输入任意用户名和密码即可</p>
        </div>
      </Card>
    </div>
  </div>
</template>

<script>
import LoginForm from '@/components/login-form'
import {login} from '@/utils/service'
export default {
  components: {
    LoginForm
  },
  methods: {
    handleSubmit ({ userName, password, rememberMe }) {
      alert('记住我' + rememberMe)
      login(userName, password, data => {
        if (data.code === 100) {
          this.$Message.success('登录成功')
          window.sessionStorage.setItem('user', JSON.stringify(data.user))
          this.$store.commit('setUser', data.user)

          // 保存7天自动登录的凭据
          if (rememberMe) {
            this.$cookies.set('rememberMe', JSON.stringify({
              username: userName,
              password: password
            }), 60 * 60 * 24 * 7)// 设置过期时间为七天
          }

          this.$router.push('/')
        } else {
          this.$Message.warning(data.msg)
        }
      })
    }
  }
}
</script>

<style>

</style>

------------------------------------------------------------------------------------------------------------------------------

对用户的密码进行MD5加密保护用户隐私
首先将数据库中的密码改为32位MD5加密后的密码。
修改后端login方法:

	@RequestMapping("/api/login")
	public Object login(String username, String password,HttpSession session) {
		User user = userDao.findByUsername(username);
		if (user == null) {
			return Result.of(102, "用户不存在");
		}
		
		String password1 = user.getPassword();// 数据库中的密码
		String password2 = MD5Util.md5(password);// 前端表单填写的密码
		
		if (!password1.equals(password2)) {
			return Result.of(103, "密码不正确");
		}
		session.setAttribute("loginUser", user);
		return Result.of(100, "登录成功").put("user", user);
	}

------------------------------------------------------------------------------------------------------------------------------

设置注销后的Cookie清除

  methods: {
    logout () {
      logout(data => {
        this.$store.commit('setUser', null)
        this.$cookies.remove('rememberMe')// 清除cookie
        this.$router.push('/login')
      })
    }
  }

------------------------------------------------------------------------------------------------------------------------------

为何要放弃Session使用Token
为了扩展性更强,适配App,所以我们放弃原有的Session系统,自己模拟一个,这个标记就叫他Token。

------------------------------------------------------------------------------------------------------------------------------

通过Header传递Token到后端
在main.js中(最前面)添加代码:

// Header携带Token
axios.defaults.headers.Token = 'HelloToken'

后端修改score方法:

	@RequestMapping("/api/score")
	public Object score(HttpSession session, HttpServletRequest request) {
		//System.out.println("当前访问者是:" + session.getId());
		System.out.println("Header-Token:" + request.getHeader("Token"));
		return Result.of(1).put("xixi", "西西"); // {code:1,"name":"西西"}
	}

运行结果:
vue+iview+springboot全栈开发_第31张图片

------------------------------------------------------------------------------------------------------------------------------

搭建Reids服务器并使用SpringBoot成功连接
在后端pom.xml文件中添加redis依赖:

	<dependency>
	    <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-starter-data-redis</artifactId>
	</dependency>

在application.yml中添加配置:

spring:
    redis:
        database: 0
        host: 127.0.0.1
        port: 6379
        password:
        timeout: 2000

在Hello.java中添加代码:

	@Autowired StringRedisTemplate srt;
	
	@RequestMapping("/api/score")
	public Object score(HttpSession session, HttpServletRequest request) {
		//System.out.println("当前访问者是:" + session.getId());
		System.out.println("Header-Token:" + request.getHeader("Token"));
		srt.opsForValue().set("西西", "xixixi");
		return Result.of(1).put("xixi", "西西"); // {code:1,"name":"西西"}
	}

访问score方法,运行结果如下:
vue+iview+springboot全栈开发_第32张图片

------------------------------------------------------------------------------------------------------------------------------

Redis保存Token信息,用户每次都携带Token值
后端login方法中添加代码:

		//session.setAttribute("loginUser", user);
		String json = new ObjectMapper().writeValueAsString(user);
		String uuid = UUID.randomUUID().toString();
		srt.opsForValue().set("User-Token:" + uuid, json, Duration.ofHours(1));
		return Result.of(100, "登录成功").put("user", user).put("token", uuid);

前端main.js中修改代码:

// Header携带Token
axios.defaults.headers.Token = window.sessionStorage.getItem('token')

login.vue中添加代码:

          axios.defaults.headers.Token = data.token
          window.sessionStorage.setItem('token', data.token)

------------------------------------------------------------------------------------------------------------------------------

通过Token获取Redis中的登录信息
后端添加方法:

	//获取当前用户自己的登录信息
	@RequestMapping("/api/user/info")
	public Object getUserInfo(HttpServletRequest request) {
		String token = request.getHeader("Token");
		String json = srt.opsForValue().get("User-Token:" + token);
		return json;
	}

前端MyHeader.vue中添加代码:

  <MenuItem name="" @click.native="getUserInfo">个人中心</MenuItem>

  methods: {
    getUserInfo () {
      this.axios.get('http://localhost:8390/api/user/info').then(response => {
        console.log(response.data)
      })
    }

------------------------------------------------------------------------------------------------------------------------------

使用SpringSession方案,客户端保存服务端下发的Token值然后每次携带
引入依赖:

	<dependency>
	    <groupId>org.springframework.session</groupId>
	    <artifactId>spring-session-data-redis</artifactId>
	</dependency>

后端主程序中添加代码:

@EnableRedisHttpSession(maxInactiveIntervalInSeconds=1800)


	@Bean
	public HeaderHttpSessionIdResolver HeaderTokenResolver() {
		return new HeaderHttpSessionIdResolver("Token");
	}

前端main.js中

        if (response.data.token) {
          window.sessionStorage.setItem('token', response.headers.token)
          this.axios.defaults.headers.Token = response.headers.token
        }

你可能感兴趣的:(前端,Web)