转载请标明出处:https://blog.csdn.net/men_ma/article/details/106847165.
本文出自 不怕报错 就怕不报错的小猿猿 的博客
spa项目开发之登录注册(vue)
前言
今日分享的是spa项目开发之登录注册,在这之前,我们要先搭建一个spa的项目,如何去搭建spa的项目呢?本篇知识与spa项目的搭建息息相关,建立在此基础之上,本博主在此附上搭建spa项目的博客链接,如下
链接: 如何使用Vue-cli搭建SPA项目?&如何在spa项目中使用路由?&嵌套路由的使用.
搭建好的spa项目结构图:
部分工具包的介绍:
另外本次目标需要两台服务器,前台(8088端口号)跟后台(8080端口号),所以需要Tomcat启动后台的服务器(eclipse),后台的项目搭建建立在maven项目基础之上
1.本次的目标
1、spa项目完成登录注册布局
2、Spa项目完成登录功能
3、 ajax 跨域问题
4、axios 的 get/post 的区别( qs )
5、T his 指针带来的变量污染
整个spa项目的结构图(贴出来):
先安装一下开发模块(命令):
npm install element-ui -S //为了显示样式,跟导入js差不多
npm install axios -S //需要ajax必须安装
npm install qs -S //为了解决get和post的区别
npm install vue-axios -S //是vue2提倡使用的轻量版的ajax
注意:一定要在项目的根路径下安装执行命令
查看上述安装是否成功安装到spa项目中去:
2.spa项目完成登录注册布局
2.1 第一步:
在这里需要用到element-ui,所以需要在main.js中导入,例如用到路由则导入路由
//导入命令
import 'element-ui/lib/theme-chalk/index.css'
//使用elementUI
Vue.use(ElementUI)
2.2 第二步:
将如下css style样式的代码复制到App.vue中覆盖:
<style>
html,
body {
width: 100%;
height: 100%;
box-sizing: border-box;
padding: 0px;
margin: 0px;
}
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
widows: 100%;
height: 100%;
}
</style>
如下所示:
2.3 第三步:
数据库:
后台逻辑代码(关键类)UserAction.java:
public class UserAction extends BaseAction implements ModelDriven<User>{
private UserBiz userBiz;
private User user = new User();
public UserBiz getUserBiz() {
return userBiz;
}
public void setUserBiz(UserBiz userBiz) {
this.userBiz = userBiz;
}
public String login() {
ObjectMapper om = new ObjectMapper();
JsonData jsonData = null;
try {
if(StringUtils.isBlank(user.getUname()) || StringUtils.isBlank(user.getPwd())) {
jsonData = new JsonData(0, "用户或者密码为空", user);
}else {
User u = this.userBiz.login(user);
// Map<String, Object> claims = new HashMap<String, Object>();
// claims.put("uname",user.getUname());
// claims.put("pwd", user.getPwd());
// String jwt = JwtUtils.createJwt(claims, JwtUtils.JWT_WEB_TTL);
// response.setHeader(JwtUtils.JWT_HEADER_KEY, jwt);
jsonData = new JsonData(1, "登录成功", u);
}
} catch (Exception e) {
e.printStackTrace();
jsonData = new JsonData(0, "用户或者密码错误", user);
}finally {
try {
ResponseUtil.write(response, om.writeValueAsString(jsonData));
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
public String getAsyncData() {
ObjectMapper om = new ObjectMapper();
try {
Thread.sleep(6000);
ResponseUtil.write(response, om.writeValueAsString("http://www.javaxl.com"));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
public User getModel() {
return user;
}
}
Login.vue:
**注意:**后台的属性名与前台的v-model绑定文本框的数据的属性名一定要一致,不然无效
<template>
<div class="login-wrap">
<el-form :model="ruleForm" ref="ruleForm" label-width="100px" class="demo-ruleForm login-container">
<h3 style="text-align: center;">用户登录</h3>
<el-form-item label="用户名" prop="unameuname">
<el-input type="uname" v-model="ruleForm.uname" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="密码" prop="pwd">
<el-input type="pwd" v-model="ruleForm.pwd" autocomplete="off"></el-input>
</el-form-item>
<el-form-item>
<el-row>
<el-col :span="24">
<div class="grid-content bg-purple-dark">
<el-button type="primary" style="width: 100%;" @click="doSub">提交</el-button>
</div>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<div class="grid-content bg-purple">
<el-link type="success" @click="toReg">用户注册</el-link>
</div>
</el-col>
<el-col :span="12">
<div class="grid-content bg-purple-light">
<el-link type="success">忘记密码</el-link>
</div>
</el-col>
</el-row>
</el-form-item>
</el-form>
</div>
</template>
<script>
/* import qs from 'qs' */ //相当于把js文件导进来,当不用http.js工具类时需要导入
export default {
data() {
return {
ruleForm: {
uname: 'zs',
pwd: '123'
}
};
},
methods: {
toReg() {
this.$router.push({
path: '/Reg'
});
},
doSub() {
//用工具类时的方法
let url = this.axios.urls.SYSTEM_USER_DOLOGIN;
//不用工具类时的方法
//let url = 'http://localhost:8080/T216_SSH/vue/userAction_login.action';
console.log(url);
//post方式提交
//这个this代表vue的实例
this.axios.post(url, this.ruleForm).then((response) => {
console.log(response);
if (response.data.code == 1) {
//这个this代表这个方法function(response)(用es6的箭头函数解决this指针带来的变量污染)
this.$message({
//登录成功消息提示
message: response.data.msg,
type: 'success'
});
} else {
this.$message({
//用户或密码错误消息提示
message: response.data.msg,
type: 'warning'
});
}
//alert(111)
//get方式提交
/* this.axios.get(url, {
params:this.ruleForm
}).then((response) => {
console.log(response);
if (response.data.code == 1) {
//这个this代表这个方法function(response)(用es6的箭头函数解决this指针带来的变量污染)
this.$message({
//登录成功消息提示
message: response.data.msg,
type: 'success'
});
} else {
this.$message({
//用户或密码错误消息提示
message: response.data.msg,
type: 'warning'
});
} */
}).catch(function(error) {
console.log(error);
});
}
}
}
</script>
<style scoped>
.login-wrap {
box-sizing: border-box;
width: 100%;
height: 100%;
padding-top: 10%;
background-image: url(data:image/svg+xml;
base64,
//这里有一个图片地址,特别长,为了博主给去掉了;
/* background-color: #112346; */
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;
background: #fff;
border: 1px solid #eaeaea;
text-align: left;
box-shadow: 0 0 20px 2px rgba(0, 0, 0, 0.1);
}
.title {
margin: 0px auto 40px auto;
text-align: center;
color: #505458;
}
</style>
2.4 第四步:
加入Login.vue组件到index.js中:
//导入vue文件
import Login from '@/views/Login'
import Reg from '@/views/Reg'
//配置路由线路
{
path: '/',
name: 'Login',
component: Login
},
{
path: '/Login',
name: 'Login',
component: Login
},
{
path: '/Reg',
name: 'Reg',
component: Reg
}
2.5 第五步:
Reg.vue:复制一下Login,vue,修改一下调用的方法就好了
2.6 看效果:
第一步:
第二步:
第三步:
3.Spa项目完成登录功能
第一步:导入工具包(两个类)
action.js:
/**
* 对后台请求的地址的封装,URL格式如下:
* 模块名_实体名_操作
*/
export default {
'SERVER': 'http://localhost:8080/T216_SSH', //服务器
'SYSTEM_USER_DOLOGIN': '/vue/userAction_login.action', //用户登陆
'SYSTEM_USER_DOREG': '/vue/userAction_reg.action', //用户注册
'SYSTEM_MENU_TREE': '/vue/treeNodeAction.action', //左侧树形菜单加载
'SYSTEM_ARTICLE_LIST': '/vue/articleAction_list.action', //文章列表
'SYSTEM_ARTICLE_ADD': '/vue/articleAction_add.action', //文章新增
'SYSTEM_ARTICLE_EDIT': '/vue/articleAction_edit.action', //文章修改
'SYSTEM_ARTICLE_DEL': '/vue/articleAction_del.action', //文章删除
'SYSTEM_USER_GETASYNCDATA': '/vue/userAction_getAsyncData.action', //vuex中的异步加载数据
'getFullPath': k => { //获得请求的完整地址,用于mockjs测试时使用
return this.SERVER + this[k];
}
}
http.js:
/**
* vue项目对axios的全局配置
*/
import axios from 'axios'
import qs from 'qs'
//引入action模块,并添加至axios的类属性urls上
import action from '@/api/action'
axios.urls = action //action相当于action.js
// axios默认配置
axios.defaults.timeout = 10000; // 超时时间
// axios.defaults.baseURL = 'http://localhost:8080/j2ee15'; // 默认地址
axios.defaults.baseURL = action.SERVER;
//整理数据
// 只适用于 POST,PUT,PATCH,transformRequest` 允许在向服务器发送前,修改请求数据
axios.defaults.transformRequest = function(data) {
data = qs.stringify(data);
return data;
};
// 请求拦截器
axios.interceptors.request.use(function(config) {
// var jwt = window.vm.$store.getters.getJwt;
// config.headers['jwt'] = jwt;
return config;
}, function(error) {
return Promise.reject(error);
});
// 响应拦截器
axios.interceptors.response.use(function(response) {
// debugger;
// var jwt = response.headers['jwt'];
// if(jwt){
// window.vm.$store.commit('setJwt',{jwt:jwt});
// }
return response;
}, function(error) {
return Promise.reject(error);
});
// // 路由请求拦截
// // http request 拦截器
// axios.interceptors.request.use(
// config => {
// //config.data = JSON.stringify(config.data);
// //config.headers['Content-Type'] = 'application/json;charset=UTF-8';
// //config.headers['Token'] = 'abcxyz';
// //判断是否存在ticket,如果存在的话,则每个http header都加上ticket
// // if (cookie.get("token")) {
// // //用户每次操作,都将cookie设置成2小时
// // cookie.set("token", cookie.get("token"), 1 / 12)
// // cookie.set("name", cookie.get("name"), 1 / 12)
// // config.headers.token = cookie.get("token");
// // config.headers.name = cookie.get("name");
// // }
// return config;
// },
// error => {
// return Promise.reject(error.response);
// });
// // 路由响应拦截
// // http response 拦截器
// axios.interceptors.response.use(
// response => {
// if (response.data.resultCode == "404") {
// console.log("response.data.resultCode是404")
// // 返回 错误代码-1 清除ticket信息并跳转到登录页面
// // cookie.del("ticket")
// // window.location.href='http://login.com'
// return
// } else {
// return response;
// }
// },
// error => {
// return Promise.reject(error.response) // 返回接口返回的错误信息
// });
export default axios;
第二步:导入api(main.js)
//导入
import axios from '@/api/http' //用了工具类时
import VueAxios from 'vue-axios'
//使用
Vue.use(VueAxios,axios)
第三步:利用axios的get/post的提交(前面Login.vue已附上)
第四步:运行结果(控制台)一定要记得启动后台Tomcat的服务器
4.ajax 跨域问题
4.1 什么叫跨域?
url地址:协议+ip+port+项目(四部分组成)
例如:
http://localhost:8080/T216_SSH/vue/treeNodeAction.action
只要四个部分中有一个部分不一样就属于跨域
例如:
http://localhost:8080/T216_SSH
http://localhost:8080/T216_SSH2
http://localhost:8088/T216_SSH
http://192.168.122.11:8080/T216_SSH
https://localhost:8088/T216_SSH
此上地址是属于跨域
附录一:ES6的语法箭头函数
doSomething(function(a){…});
doSomething((a)=>{});
过滤器CorsFilter.java
/**
* 配置tomcat允许跨域访问
*
* @author Administrator
*
*/
public class CorsFilter 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.addHeader("Access-Control-Allow-Origin", "*");// *,任何域名
// httpResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT,
// DELETE");
// // httpResponse.setHeader("Access-Control-Allow-Headers", "Origin,
// // X-Requested-With, Content-Type, Accept");
//
// // 允许请求头Token
// httpResponse.setHeader("Access-Control-Allow-Headers",
// "Origin,X-Requested-With, Content-Type, Accept, Token");
// HttpServletRequest req = (HttpServletRequest) servletRequest;
// System.out.println("Token=" + req.getHeader("Token"));
// if("OPTIONS".equals(req.getMethod())) {
// return;
// }
//
//
// filterChain.doFilter(servletRequest, servletResponse);
// }
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletResponse resp = (HttpServletResponse) servletResponse;
HttpServletRequest req = (HttpServletRequest) servletRequest;
// Access-Control-Allow-Origin就是我们需要设置的域名
// Access-Control-Allow-Headers跨域允许包含的头。
// Access-Control-Allow-Methods是允许的请求方式
resp.setHeader("Access-Control-Allow-Origin", "*");// *,任何域名
resp.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE");
// resp.setHeader("Access-Control-Allow-Headers", "Origin,X-Requested-With,
// Content-Type, Accept");
// 允许客户端,发一个新的请求头jwt
resp.setHeader("Access-Control-Allow-Headers", "Origin,X-Requested-With, Content-Type, Accept, jwt");
// 允许客户端,处理一个新的响应头jwt
resp.setHeader("Access-Control-Expose-Headers", "jwt");
// String sss = resp.getHeader("Access-Control-Expose-Headers");
// System.out.println("sss=" + sss);
// 允许请求头Token
// httpResponse.setHeader("Access-Control-Allow-Headers","Origin,X-Requested-With,
// Content-Type, Accept, Token");
// System.out.println("Token=" + req.getHeader("Token"));
if ("OPTIONS".equals(req.getMethod())) {// axios的ajax会发两次请求,第一次提交方式为:option,直接返回即可
return;
}
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
}
web.xml中配置:
注1:axios跨域问题
会一直报错:“http://127.0.0.1:8848' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header”
因为使用了前后端分离开发,跨域访问了,解决方案:需要配置tomcat允许跨域访问,
tomcat跨域配置方法很多,但最简单的方式是自己写一个过滤器CorsFilter实现,添加一个响应头
Access-Control-Allow-Origin即可
httpResponse.addHeader("Access-Control-Allow-Origin", "*");//*表示任何域名
httpResponse.addHeader("Access-Control-Allow-Origin", "http://localhost:80");
Access-Control-Allow-Origin:* #则允许所有域名的脚本访问该资源。
Access-Control-Allow-Origin:https://www.fujieace.com #允许特定的域名访问
注2:axios.get提交没有问题,axios.post提交后台接收不到数据
因为POST提交的参数的格式是Request Payload,这样后台取不到数据的
解决方案:使用qs.js库,将{a:'b',c:'d'}转换成'a=b&c=d'
注3:为简化axios使用,还可以使用axios全局配置及拦截器,详情见资料“api/http.js”
axios.defaults.baseURL = 'https://api.example.com';
//axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;//自定义请求头,添加认证令牌
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
注4:为方便开发,建议对请求地址进行封装,详情见资料“api/action.js”
注5:^_^~~~~为进一步简化开发,将action.js的URL地址封装到axios.urls属性上
5.axios 的 get/post 的区别( qs )
1.题外话:
vue.js有著名的全家桶系列:vue-router,vuex, vue-resource,再加上构建工具vue-cli,就是一个完整的vue项目的核心构成。
其中vue-resource是Vue.js的一款插件,它可以通过XMLHttpRequest或JSONP发起请求并处理响应,但在vue更新到2.0之后,
作者就宣告不再对vue-resource更新,而是推荐的axios
2.GET提交
axios.get('/user', {//注意数据是保存到json对象的params属性
params: {
ID: 12345
}
}).then(function (response) {
console.log(response);
}).catch(function (error) {
console.log(error);
});
3.POST提交
axios.post('/user', {//注意数据是直接保存到json对象
firstName: 'Fred',
lastName: 'Flintstone'
}).then(function (response) {
console.log(response);
}).catch(function (error) {
console.log(error);
});
6.This 指针带来的变量污染
我太难了