github地址

https://github.com/PanJiaChen/vue-admin-template

新手踩坑

https://www.jianshu.com/p/290cd0060d04

项目目录

在这里插入图片描述

项目中有如下目录

  • build:编译用到的脚本
  • mock:模拟后台服务器接口,可以产生数据
  • node_modules:node第三方包,这个目录可以删掉,通过npm/cnpm install命令可以下载
  • public:暂时没学习到
  • src:源代码文件,这里通常是我们写代码的地方
  • tests:测试文件

跨域问题

https://zhuanlan.zhihu.com/p/53545472

前端

在vue.config.js中添加如下代码

proxy: {
      '/api': {
        target: 'process.env.VUE_APP_BASE_API',
        changeOrigin: true,
        pathRewrite: {
          '^/api': 'api'
        }
      }
    },

然后在.env.development中

VUE_APP_BASE_API = 'http://localhost:8080/'

后端

在config包下配置

@Configuration
public class MyConfiguration {
    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**");
            }
        };
    }
}

登录功能

在src/views/login下的index.js中可以发现,点击登录所绑定的事件click.native.prevent="handleLogin"

<el-button 
   :loading="loading" 
   type="primary" 
   style="width:100%;margin-bottom:30px;" 
   @click.native.prevent="handleLogin">Login
</el-button>

在下方的脚本中找到handleLogin()

// views/login
handleLogin() {
      this.$refs.loginForm.validate(valid => {
        if (valid) {
          this.loading = true
          this.$store.dispatch('user/login', this.loginForm).then(() => {
            this.$router.push({ path: this.redirect || '/' })
            this.loading = false
          }).catch(() => {
            this.loading = false
          })
        } else {
          console.log('error submit!!')
          return false
        }
      })
    }

this.$refs.loginForm 调用了loginForm的validate方法,传入了一个回调函数,参数为valid,代表是否验证成功

this.$store.dispatch(‘user/login’, this.loginForm) 中第一个参数本应该是action的方法名,但是由于store/index.js使用了命名空间

关于命名空间https://vuex.vuejs.org/zh/guide/modules.html#命名空间

// store/index.js
const store = new Vuex.Store({
  modules: {
    app,
    settings,
    user
  },
  getters
})

user下的login()方法被映射为user/login,所以这句代码将转交给vuex的user下的action : login()处理

// store/modules/user
// user login
import { login, logout, getInfo } from '@/api/user'
import { getToken, setToken, removeToken } from '@/utils/auth'
import { resetRouter } from '@/router'

const actions = {
  // user login
  login({ commit }, userInfo) {
    const { username, password } = userInfo
    return new Promise((resolve, reject) => {
      login({ username: username.trim(), password: password }).then(response => {
        const { data } = response
        commit('SET_TOKEN', data.token)
        setToken(data.token)
        resolve()
      }).catch(error => {
        reject(error)
      })
    })
  }
} 

login({ commit }, userInfo) 接收两个参数,第一个commit是vuex的固定语法,用于调用mutation方法,第二个参数为loginForm

const { username, password } = userInfo

这里把userInfo中的参数解包,用两个新的变量接收

这里用了Promise对象https://www.jianshu.com/p/b16e7c9e1f9f,类似于try,catch的体系

login({ username: username.trim(), password: password }) 调用了api请求(封装过的axios请求,可在utils/request.js中查看)

传入了一个json对象

{
	'username': username.trim(),
	'password':password
}

SpringMVC可以接收这个参数,当然这里用的mock模拟服务器,首先在api/user中找到login方法

export function login(data) {
  return request({
    url: '/vue-admin-template/user/login',
    method: 'post',
    data
  })
}

然后在mock/user中发现这个请求对应的处理方法

const tokens = {
  admin: {
    token: 'admin-token'
  },
  editor: {
    token: 'editor-token'
  }
}

module.exports = [
  // user login
  {
    url: '/vue-admin-template/user/login',
    type: 'post',
    response: config => {
      const { username } = config.body
      const token = tokens[username]
      // mock error
      if (!token) {
        return {
          code: 60204,
          message: 'Account and password are incorrect.'
        }
      }
      return {
        code: 20000,
        data: token
      }
    }
  }
]

这里的config个人猜测,应该是requset请求,config.body为请求体,前面分析传入了一个json对象,这里config.body就是那个json对象

可以看出,返回的是一个json对象

const tokens = {
  admin: {
    token: 'admin-token'
  },
  editor: {
    token: 'editor-token'
  }
}
{
	code: 123456,
	message: 'Account and password are incorrect.'
	date: {token}
}

通过这里的分析,在后端Controller对象中返回一个token,结果发现一直报错,然后打开utils/request.js

这里是用axios拦截器对请求和响应进行处理,然后发现如下代码

const res = response.data
    // if the custom code is not 20000, it is judged as an error.
    if (res.code !== 20000) {
      Message({
        message: res.message || 'Error',
        type: 'error',
        duration: 5 * 1000
      })

在这里console.log(response)发现问题

{
    "data": {       
    	"token": "admin-token"
    },
    "status": 200,
    "statusText": "",
    "headers": {
        "content-type": "application/json"
    },
    "config": {
        "transformRequest": {},
        "transformResponse": {},
        "timeout": 5000,
        "xsrfCookieName": "XSRF-TOKEN",
        "xsrfHeaderName": "X-XSRF-TOKEN",
        "maxContentLength": -1,
        "headers": {
            "Accept": "application/json, text/plain, */*",
            "Content-Type": "application/json;charset=utf-8"
        },
        "method": "post",
        "baseURL": "http://localhost:8080/",
        "url": "http://localhost:8080/api/user/login",
        "data": "{\"username\":\"admin\",\"password\":\"111111\"}"
    },
    "request": {}
}

response.data应该具有如下格式

{
	code: 123456,
	message: 'Account and password are incorrect.'
	date: {token}
}

于是自定义了一个CommonResult类如下

@Data
public class CommonResult<T> {
    private Integer code;
    private String message;
    private T data;
}
@RequestMapping(value = "/login") 
public CommonResult<Object> login(){
	System.out.println("login了");
    UserLogin userLogin = new UserLogin();
    userLogin.setToken("admin-token");
    CommonResult<Object> result = new CommonResult<>();
    result.setCode(20000);
    result.setData(userLogin);
    return result;
}

从这里可以了解到,controller通过@ResponseBody或者@RestController返回一个对象时,对象首先被转换为json格式,然后封装在response中的data属性里面

随后遇到的问题与上面差不多,同样的思路可以解决

Logo

前往低代码交流专区

更多推荐