ElementUI实现登录注册+axios全局配置+CORS跨域

一、搭建项目

1.1 安装 Element-UI

先确保是否安装了vue-cli脚手架工具 !!!

安装vue脚手架可以看看我的上一篇博客

构建好项目后通过npm安装element-ui

cd 项目根路径                               #进入新建项目的根目录
npm install element-ui -S                  #安装element-ui模块

1.2 导入组件

打开 src目录下的main.js,该文件是项目的入口文件,所以在这里导入,其他组件均可使用,不用再导入。

import Vue from 'vue'
 
//新添加1
import ElementUI from 'element-ui'
//新增加2,避免后期打包样式不同,要放在import App from './App';之前
import 'element-ui/lib/theme-chalk/index.css'
 
import App from './App'
import router from './router'
 
Vue.use(ElementUI)   //新添加3
Vue.config.productionTip = false

1.3 创建登录、注册界面

我在src目录下新建了一个views专门存放一些界面组件,界面可自己设计,以下是我编写的:

1. 创建用户登录组件Login.vue

<template>
  <div class="login-wrap">
    <el-form class="login-container">
      <h1 class="title">用户登录</h1>
      <el-form-item label="">
        <el-input type="text" v-model="username" placeholder="登录账号" autocomplete="off"></el-input>
      </el-form-item>
      <el-form-item label="">
        <el-input type="password" v-model="password" placeholder="登录密码" autocomplete="off"></el-input>
      </el-form-item>
      <el-form-item>
        <el-button type="warning" style="width:100%;" @click="doSubmit()">提交</el-button>
      </el-form-item>
      <el-row style="text-align: center;margin-top:-10px">
        <el-link type="primary">忘记密码</el-link>
        <el-link type="primary" @click="gotoRegister()">用户注册</el-link>
      </el-row>
    </el-form>
  </div>
</template>
 
<script>
  export default {
    name: 'Login',
    data() {
      return {
        username: '',
        password: ''
      }
    },
    methods: {
      gotoRegister() {
        this.$router.push("/Register");
      }
    }
  }
</script>
 
<style scoped>
  .login-wrap {
   box-sizing: border-box;
   width: 100%;
   height: 100%;
   padding-top: 10%;
  background-color: #3b7cf5;
   background-repeat: no-repeat;
   background-position: center right;
   background-size: 100%;
  }
 
  .login-container {
   border-radius: 10px;
   margin: 0px auto;
   width: 350px;
   padding: 30px 35px 15px 35px;
   border: 1px solid #eaeaea;
   text-align: left;
   background-color: rgba(229, 229, 229, 0.8);
  }
 
  .title {
    margin: 0px auto 40px auto;
    text-align: center;
    color: #0b0b0b;
  }
</style>

 创建用户注册组件Register.vue

<template>
  <div class="login-wrap">
    <el-form class="login-container">
      <h1 class="title">用户注册</h1>
      <el-form-item label="">
        <el-input type="text" v-model="username" placeholder="注册账号" autocomplete="off"></el-input>
      </el-form-item>
      <el-form-item label="">
        <el-input type="password" v-model="password" placeholder="注册密码" autocomplete="off"></el-input>
      </el-form-item>
      <el-form-item>
        <el-button type="warning" style="width:100%;" @click="doSubmit()">提交</el-button>
      </el-form-item>
      <el-row style="text-align: center;margin-top:-10px">
        <el-link type="primary">忘记密码</el-link>
        <el-link type="primary" @click="gotoLogin()">用户注册</el-link>
      </el-row>
    </el-form>
  </div>
</template>
 
<script>
  export default {
    name: 'Register',
    data() {
      return {
        username: '',
        password: ''
      }
    },
    methods: {
      gotoLogin() {
        this.$router.push("/");
      }
    }
  }
</script>
 
<style scoped>
  .login-wrap {
    box-sizing: border-box;
    width: 100%;
    height: 100%;
    padding-top: 10%;
 
    background-color: #3b7cf5;
    background-repeat: no-repeat;
    background-position: center right;
    background-size: 100%;
  }
 
  .login-container {
    border-radius: 10px;
    margin: 0px auto;
    width: 350px;
    padding: 30px 35px 15px 35px;
    border: 1px solid #eaeaea;
    text-align: left;
    background-color: rgba(229, 229, 229, 0.8);
  }
 
  .title {
    margin: 0px auto 40px auto;
    text-align: center;
    color: #0b0b0b;
  }
</style>

注1:<style scoped>
        在vue组件中,在style标签上添加scoped属性,以表示它的样式作用于当下的模块,很好的实现了样式私有化的目的

注2:auto-complete="off"
        autocomplete 属性是 HTML5 中的新属性,off-----禁用自动完成

 2. 配置路由

import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
// 导入Login登录组件
import Login from '@/views/Login'
// 导入Register注册组件
import Register from '@/views/Register'
 
Vue.use(Router)
 
export default new Router({
  routes: [
    {
      path: '/',
      name: 'Login',
      component: Login
    },{
      path: '/Register',
      name: 'Register',
      component: Register
    }
  ]
})

3. 运行效果

在项目根目录执行 npm run dev 指令

界面效果:

二、后台交互

2.1 引入axios

        axios是vue2提倡使用的轻量版的ajax。它是基于promise的HTTP库。它会从浏览器中创建XMLHttpRequests,与Vue配合使用非常好。

Tips:vue.js有著名的全家桶系列:vue-router,vuex, vue-resource,再加上构建工具vue-cli,就是一个完整的vue项目的核心构成。 其中vue-resource是Vue.js的一款插件,它可以通过XMLHttpRequest或JSONP发起请求并处理响应,但在vue更新到2.0之后,作者就宣告不再对vue-resource更新,而是推荐的axios

安装指令: 

npm i axios -S

2.2 添加vue-axios的全局配置

        Axios是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,本质上也是对原生XHR的封装,只不过它是Promise的实现版本,符合最新的ES规范。

vue-axios是在axios基础上扩展的插件,在Vue.prototype原型上扩展了$http等属性,可以更加方便的使用axios。

通过vue-axios实现对axios的轻量封装:

第一步:下载安装vue-axiosqs

npm i vue-axios -S

qs库用于解决POST请求问题,因为POST提交的参数的格式是Request Payload,这样后台取不到数据的。 

npm install qs -S 

 

第二步:导入api模块,添加axios的全局配置

     在SPA项目的src目录下添加api模块,其中api模块包含了action.js(针对后台请求接口的封装定义)和http.js(针对axios的全局配置)两个文件。

  • action.js

/**
 * 对后台请求的地址的封装,URL格式如下:
 * 模块名_实体名_操作
 */
export default {
	'SERVER': 'http://localhost:8080/ssm_vue', //服务器
	'SYSTEM_USER_DOLOGIN': '/user/userLogin', //登陆
	'SYSTEM_USER_DOREG': '/user/userRegister', //注册
	'getFullPath': k => { //获得请求的完整地址,用于mockjs测试时使用
		return this.SERVER + this[k];
	}
}

 对后台请求的地址的封装,URL格式:模块名实体名操作

2.2 ssm项目准备 (后端)

2.2.1 准备数据表

2.2.2 导入ssm项目

可以创建一个新项目连接数据库自动生成代码,并修改jdk和maven路径

2.2.3 编写控制器
package com.zking.ssm.controller;

import com.zking.ssm.service.IUserService;
import com.zking.ssm.util.JsonResponseBody;
import com.zking.ssm.util.PageBean;
import com.zking.ssm.vo.UserVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.zking.ssm.jwt.*;

@Controller
@RequestMapping("/user")
public class UserController {

    @Autowired
    private IUserService userService;

    @RequestMapping("/userLogin")
    @ResponseBody
    public JsonResponseBody<?> userLogin(UserVo userVo, HttpServletResponse response){
        if(userVo.getUsername().equals("lwh")&&userVo.getPassword().equals("123")){
            //私有要求claim
//            Map<String,Object> json=new HashMap<String,Object>();
//            json.put("username", userVo.getUsername());
            //生成JWT,并设置到response响应头中
//            String jwt=JwtUtils.createJwt(json, JwtUtils.JWT_WEB_TTL);
//            response.setHeader(JwtUtils.JWT_HEADER_KEY, jwt);
            return new JsonResponseBody<>("用户登陆成功!",true,0,null);
        }else{
            return new JsonResponseBody<>("用户名或密码错误!",false,0,null);
        }
    }

    @RequestMapping("/queryUserPager")
    @ResponseBody
    public JsonResponseBody<List<Map<String,Object>>>
            queryUserPager(UserVo userVo, HttpServletRequest request){
        try {
            PageBean pageBean=new PageBean();
            pageBean.setRequest(request);
            List<Map<String, Object>> users = userService.queryUserPager(userVo, pageBean);
            return new JsonResponseBody<>("OK",true,pageBean.getTotal(),users);
        } catch (Exception e) {
            e.printStackTrace();
            return new JsonResponseBody<>("分页查询用户信息失败!",false,0,null);
        }

    }





    //注册方法
    @RequestMapping("/userRegister")
    @ResponseBody
    public JsonResponseBody<?> userRegister(UserVo user, HttpServletResponse response) {
        int i = userService.insertSelectives(user);
        if (i > 0) {
            return new JsonResponseBody<>("用户注册成功!", true, 0, null);
        } else {
            return new JsonResponseBody<>("用户注册失败!", false, 0, null);
        }
    }

}

2.3 前端编写

1. 在Login.vue提交按钮的监听函数中加入发送get请求的代码:

<template>
    <div class="login-wrap">
      <el-form class="login-container">
        <h1 class="title">用户登录</h1>
        <el-form-item label="">
          <el-input type="text" v-model="username" placeholder="登录账号" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="">
          <el-input type="password" v-model="password" placeholder="登录密码" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="warning" style="width:100%;" @click="doSubmit()">提交</el-button>
        </el-form-item>
        <el-row style="text-align: center;margin-top:-10px">
          <el-link type="primary">忘记密码</el-link>
          <el-link type="primary" @click="gotoRegister()">用户注册</el-link>
        </el-row>
      </el-form>
    </div>
  </template>
   
   <script>
   export default {
     name: 'Login',
     data() {
       return {
         username: '',
         password: ''
       }
     },
     methods: {
       gotoRegister() {
         this.$router.push("/Register");
       },
       doSubmit() {
         //定义后台登录方法连接地址
         let url = this.axios.urls.SYSTEM_USER_DOLOGIN;
         //获取数据
         let params = {
           username: this.username,
           password: this.password
         };
         /* get请求进行参数传递 */
         this.axios.get(url, {params:params}).then(r => {
           console.log(r);
            //判断是否登录成功
            if (r.data.success) {
              //利用ElementUI信息提示组件返回登录信息
              this.$message({
                message: r.data.msg,
                type: 'success'
              });
              //登陆成功,返回指定界面
              this.$route.push('主界面');
            } else {
              //弹出登录失败信息
              this.$message.error(r.data.msg);
            }
          }).catch(e => {
            //异常信息
          });
  
         /* post请求方式 */
         /* this.axios.post(url, params).then(r => {
           console.log(r);
           //判断是否登录成功
           if (r.data.success) {
             //利用ElementUI信息提示组件返回登录信息
             this.$message({
               message: r.data.msg,
               type: 'success'
             });
             //登陆成功,返回指定界面
             this.$route.push('主界面');
           } else {
             //弹出登录失败信息
             this.$message.error(r.data.msg);
           }
         }).catch(function(error) {
           console.log(error);
         }); */
       }
     }
   }
 </script>
   
  <style scoped>
    .login-wrap {
     box-sizing: border-box;
     width: 100%;
     height: 100%;
     padding-top: 10%;
    background-color: #3b7cf5;
     background-repeat: no-repeat;
     background-position: center right;
     background-size: 100%;
    }
   
    .login-container {
     border-radius: 10px;
     margin: 0px auto;
     width: 350px;
     padding: 30px 35px 15px 35px;
     border: 1px solid #eaeaea;
     text-align: left;
     background-color: rgba(229, 229, 229, 0.8);
    }
   
    .title {
      margin: 0px auto 40px auto;
      text-align: center;
      color: #0b0b0b;
    }
  </style>

2. 在Register.vue提交按钮的监听函数中加入发送post请求的代码:

<template>
    <div class="login-wrap">
      <el-form class="login-container">
        <h1 class="title">用户注册</h1>
        <el-form-item label="">
          <el-input type="text" v-model="username" placeholder="注册账号" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="">
          <el-input type="password" v-model="password" placeholder="注册密码" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="warning" style="width:100%;" @click="doSubmit()">提交</el-button>
        </el-form-item>
        <el-row style="text-align: center;margin-top:-10px">
          <el-link type="primary">忘记密码</el-link>
          <el-link type="primary" @click="gotoLogin()">用户登录</el-link>
        </el-row>
      </el-form>
    </div>
  </template>
   
   <script>
   export default {
     name: 'Register',
     data() {
       return {
         username: '',
         password: ''
       }
     },
     methods: {
       gotoLogin() {
         this.$router.push("/");
       },
       doSubmit() {
         //定义后台注册方法连接地址
         let url = this.axios.urls.SYSTEM_USER_DOREG;
         //获取数据
         let params = {
           username: this.username,
           password: this.password
         };
  
         /* post请求方式 */
         this.axios.post(url, params).then(r => {
           //判断是否注册成功
           if (r.data.success) {
             //利用ElementUI信息提示组件返回登录信息
             this.$message({
               message: r.data.msg,
               type: 'success'
             });
             //注册成功,返回指定界面
             //this.$route.push('主界面');
           } else {
             //弹出注册失败信息
             this.$message.error(r.data.msg);
           }
         }).catch(function(error) {
           console.log(error);
         });
       }
     },
   }
 </script>
  <style scoped>
    .login-wrap {
      box-sizing: border-box;
      width: 100%;
      height: 100%;
      padding-top: 10%;
   
      background-color: #3b7cf5;
      background-repeat: no-repeat;
      background-position: center right;
      background-size: 100%;
    }
   
    .login-container {
      border-radius: 10px;
      margin: 0px auto;
      width: 350px;
      padding: 30px 35px 15px 35px;
      border: 1px solid #eaeaea;
      text-align: left;
      background-color: rgba(229, 229, 229, 0.8);
    }
   
    .title {
      margin: 0px auto 40px auto;
      text-align: center;
      color: #0b0b0b;
    }
  </style>

2.4 登入测试

1. 启动ssm项目,部署tomcat服务器

2. 运行vue项目 —— 指令:npm run dev

注:项目运行时默认使用的是8080端口,如果其他程序也使用该端口则会引发冲突,如果tomcat默认使用的也是8080,为避免冲突需要改变端口号。
打开项目目录下config/index.js文件,修改dev部分的port即可

 运行项目:

目前我有个问题,就是我在发送请求的时候,报出了个跨域的问题,但是我明明配置了,上网查了一下,说是有可能是配置过滤器的顺序问题,但是我改了之后还是一样,这里我还是记录一下,有没有大佬知道的   错误信息

三、CORS跨域

3.1 跨域请求问题

因为我们采用的是前后端分离的方式进行开发,前端和后端分别泡在不同的服务器上,基于安全性考虑,浏览器有同源策略,所以出现了跨域问题。
        同源策略[same origin policy]是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。 同源策略是浏览器安全的基石。

3.2 跨域问题处理

解决方案:
        需要配置tomcat允许跨域访问,tomcat跨域配置方法很多,在学springboot之前最简单的方式是自己写一个过滤器CorsFilter实现,添加一个响应头Access-Control-Allow-Origin即可

package com.zking.ssm.util;
 
import java.io.IOException;
 
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
 
/**
 * 配置tomcat允许跨域访问
 * 
 * @author Administrator
 *
 */
public class CorsFilter2 implements Filter {
 
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
	}
 
	@Override
	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
			throws IOException, ServletException {
		HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
 
		// Access-Control-Allow-Origin就是我们需要设置的域名
		// Access-Control-Allow-Headers跨域允许包含的头。
		// Access-Control-Allow-Methods是允许的请求方式
		httpResponse.setHeader("Access-Control-Allow-Origin", "*");// *,任何域名
		httpResponse.setHeader("Access-Control-Allow-Headers", "responseType,Origin, X-Requested-With, Content-Type, Accept");
		httpResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE");
 
		//允许客户端处理一个新的响应头jwt
		//httpResponse.setHeader("Access-Control-Expose-Headers", "jwt,Content-Disposition");
		filterChain.doFilter(servletRequest, servletResponse);
	}
 
	@Override
	public void destroy() {
 
	}
}

 web.xml 配置请求拦截

  <!--CrosFilter跨域过滤器-->
  <filter>
    <filter-name>corsFilter</filter-name>
    <filter-class>com.zking.ssm.util.CorsFilter2</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>corsFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>


 

Guess you like

Origin blog.csdn.net/Ying_hao_kun/article/details/133254168