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

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

一、搭建项目


1.1 安装 Element-UI

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

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


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

cd 项目根路径                               #进入新建项目的根目录

npm install element-ui -S                  #安装element-ui模块

bed8f0f560404093b8e402f84716b783.png


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 指令

界面效果:

e1571080bf6c43eca8b9d8eb7e46da5d.png


二、后台交互


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

0c7d987459514655aa8d5cf9d6958dca.png


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

1a7d5d46c2624ce590ebaced7a6053aa.png

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

npm install qs -S

bab5130f3cb549b2819c3fd2e20b13dd.png

第二步:导入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.3 ssm项目准备 (后端)


2.3.1 准备数据表

73f396fd057040d59cb54dd045a37a14.png

2.3.2 导入ssm项目

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

9564bb54ff8040348f36890505056836.png

2.3.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.4 前端编写

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.5 登入测试

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

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

注:项目运行时默认使用的是8080端口,如果其他程序也使用该端口则会引发冲突,如果tomcat默认使用的也是8080,为避免冲突需要改变端口号。

打开项目目录下config/index.js文件,修改dev部分的port即可

d3579c8ffb77429b9b3ef3031f642ea6.png

运行项目:

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

cecbd49791344fe1b2f9552367d09e6d.png


三、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>


目录
相关文章
|
11天前
|
JSON 安全 前端开发
浅析CORS跨域漏洞与JSONP劫持
浅析CORS跨域漏洞与JSONP劫持
30 3
|
1月前
|
安全
CORS 跨域资源共享的实现原理
CORS 跨域资源共享的实现原理
|
2月前
|
Web App开发 JSON 数据格式
【Azure Developer】浏览器查看本地数据文件时遇见跨域问题(CORS)
【Azure Developer】浏览器查看本地数据文件时遇见跨域问题(CORS)
【Azure Developer】浏览器查看本地数据文件时遇见跨域问题(CORS)
|
2月前
|
API
【Azure Function】Function本地调试时遇见跨域问题(blocked by CORS policy)
【Azure Function】Function本地调试时遇见跨域问题(blocked by CORS policy)
【Azure Function】Function本地调试时遇见跨域问题(blocked by CORS policy)
|
2月前
|
安全 前端开发 Java
Web端系统开发解决跨域问题——以Java SpringBoot框架配置Cors为例
在Web安全上下文中,源(Origin)是指一个URL的协议、域名和端口号的组合。这三个部分共同定义了资源的来源,浏览器会根据这些信息来判断两个资源是否属于同一源。例如,https://www.example.com:443和http://www.example.com虽然域名相同,但由于协议和端口号不同,它们被视为不同的源。同源(Same-Origin)是指两个URL的协议、域名和端口号完全相同。只有当这些条件都满足时,浏览器才认为这两个资源来自同一源,从而允许它们之间的交互操作。
Web端系统开发解决跨域问题——以Java SpringBoot框架配置Cors为例
|
2月前
|
安全 开发者 UED
|
2月前
|
前端开发 JavaScript
【Azure 环境】前端Web通过Azure AD获取Token时发生跨域问题(CORS Error)
【Azure 环境】前端Web通过Azure AD获取Token时发生跨域问题(CORS Error)
|
3月前
|
安全
CORS 跨域资源共享的实现原理
CORS 跨域资源共享的实现原理
|
2月前
|
前端开发 应用服务中间件 API
"揭秘!面试官必问:你是如何巧妙绕过跨域难题的?前端代理VS服务器端CORS,哪个才是你的秘密武器?"
【8月更文挑战第21天】在软件开发中,尤其前后端分离架构下,跨域资源共享(CORS)是常见的挑战。主要解决方案有两种:一是服务器端配置CORS策略,通过设置响应头控制跨域访问权限,无需改动前端代码,增强安全性;二是前端代理转发,如使用Nginx或Webpack DevServer在开发环境中转发请求绕过同源策略,简化开发流程但不适用于生产环境。生产环境下应采用服务器端CORS策略以确保安全稳定。
35 0
|
2月前
|
JavaScript 前端开发
【Vue面试题二十五】、你了解axios的原理吗?有看过它的源码吗?
这篇文章主要讨论了axios的使用、原理以及源码分析。 文章中首先回顾了axios的基本用法,包括发送请求、请求拦截器和响应拦截器的使用,以及如何取消请求。接着,作者实现了一个简易版的axios,包括构造函数、请求方法、拦截器的实现等。最后,文章对axios的源码进行了分析,包括目录结构、核心文件axios.js的内容,以及axios实例化过程中的配置合并、拦截器的使用等。
【Vue面试题二十五】、你了解axios的原理吗?有看过它的源码吗?