spa项目开发之登录注册(vue)

转载请标明出处:https://blog.csdn.net/men_ma/article/details/106847165.
本文出自 不怕报错 就怕不报错的小猿猿 的博客

前言

今日分享的是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 指针带来的变量污染

在这里插入图片描述
在这里插入图片描述

我太难了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值