前后端分离项目之登录页面(前后端请求、响应和连接数据库)

目录

一、前端登录发起请求

二、后端请求接收

三、连接数据库

四、后端响应

五、前端处理

六、在前端验证用户是否登录

七、web会话跟踪

八、请求拦截器和响应拦截器


本文Vue-cli前端项目基于文章:

Vue-cli搭建项目(包含Node.js安装和ElementUI安装)_小俱的一步步的博客-CSDN博客

后端javaEE项目基于文章:

创建web后端程序(servlet程序搭建)_小俱的一步步的博客-CSDN博客

一、前端登录发起请求

1.安装axios,使用框架

        axios 是一个 HTTP 的网络请求库,安装 npm install axios;

        在 main.js 中配置 axios,导入网络请求库:import axios from 'axios';

        设置访问后台服务器地址:axios.defaults.baseURL="http://127.0.0.1:8080/webBack/";

        将 axios 挂载到 vue 全局对象中,使用 this 可以直接访问:Vue.prototype.$http=axios;

//网络请求
//导入 axios
import axios from 'axios';
//设置访问后台服务器地址
axios.defaults.baseURL = "http://127.0.0.1:8080/webBack/";
//将 axios 挂载到 vue 全局对象中,使用 this 可以直接访问
Vue.prototype.$http = axios;

2.组装请求数据:

        在Login(登录)组件中获取前端数据:

前后端分离项目之登录页面(前后端请求、响应和连接数据库)_第1张图片

      data() {
			return {
				form: {
					account: '',
					password: ''
				}
			}
		},

        由于向前端提供的数据为json格式,后端不识别,因此将json对象序列化为键=值&键=值:

	//将json对象序列化为键=值&键=值
	function jsonToString(jsonobj) {
		console.log(jsonobj)
		var str = "";
		for (var s in jsonobj) {
			str += s + "=" + jsonobj[s] + "&";
		}
		return str.substring(0, str.length - 1);
	}

二、后端请求接收

        创建LoginServlet 类继承 HttpServlet 类,req.getParameter("")接收前端数据

三、连接数据库

1.创建数据库,创建管理员表

CREATE DATABASE web_db CHARSET utf8

CREATE TABLE admin(
	id INT PRIMARY KEY AUTO_INCREMENT,
	account VARCHAR(20) UNIQUE,
	PASSWORD VARCHAR(20)
)

封装用户信息:创建Admin类 属性有int id,String account,String password;生成Getter ,Setter方法。

2.jdbc连接数据库:

import java.sql.*;

public class LoginDao {
    public Admin login(String account, String password) throws ClassNotFoundException, SQLException {
        Connection connection = null;
        PreparedStatement ps = null;
        Admin admain = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");//初始化驱动程序
            String url ="jdbc:mysql://127.0.0.1:3306/web_db?serverTimezone=Asia/Shanghai";
            String uname="root";
            String pwd ="123456";
            connection = DriverManager.getConnection(url,uname,pwd);
            ps = connection.prepareStatement("SELECT id,account FROM admin WHERE account = ?AND password = ?");
            ps.setObject(1,account);
            ps.setObject(2,password);
            ResultSet rs = ps.executeQuery();
            while (rs.next()){
                admain = new Admin();
                admain.setId(rs.getInt("id"));
                admain.setAccount(rs.getString("account"));
            }
        }finally {
            if (connection!=null){
                connection.close();
            }
            if (ps!=null){
                ps.close();
            }
        }
        return admain;
    }
}

        本次后端项目目录: 

 前后端分离项目之登录页面(前后端请求、响应和连接数据库)_第2张图片

其中LoginDao放在dao包中 ,Admin放在model包中。

四、后端响应

1.接收到dao返回的查询数据

2.进行数据封装,创建一个CommonResult类,封装后端数据,必须有get、set方法 ,否则转json时会报错,三个属性:

    private int code;//自定义状态码
    private Object data;//数据
    private String message;//消息

3.进行逻辑判断: 根据前端传入的admin数据进行判断,并响应自定义的状态码,都是用封装的CommonResult类转为json格式传递。

后端接收和响应代码:

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;



public class LoginServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String account = req.getParameter("account");
        String password = req.getParameter("password");
        System.out.println(account+":"+password);
        //设置响应代码
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter printWriter = resp.getWriter();
        CommonResult commonResult = null;
        try{
            LoginDao loginDao = new LoginDao();
            Admin admin = loginDao.login(account,password);
            if (admin!=null){
                String token = JWTUtil.getToken(admin);
                admin.setToken(token);
                commonResult = new CommonResult(200,admin,"登录成功");

            }else {
                commonResult = new CommonResult(201,"账号密码错误");
            }
        }catch (Exception e){
            e.printStackTrace();
            commonResult = new CommonResult(500,"系统忙");
        }
        ObjectMapper objectMapper = new ObjectMapper();
        String json = objectMapper.writeValueAsString(commonResult);
        printWriter.print(json);
    }
}

五、前端处理

1.接收后端响应的数据:resp.data接收

this.$http.get("back/test").then((resp) => {
		if (resp.data.code == 200) {

		}
}

2.前端路由跳转:登录账号密码与数据库中的匹配,页面跳转到/main,也就是路由跳转,在index.js中配置。

//路由导航守卫,每次进行路由跳转时,就会自动的执行此段逻辑
rout.beforeEach((to, from, next) => {
	if (to.path == '/') {//由于自己定义的login组件的地址为“/”
		// 如果用户访问的登录页,nest直接放行
		return next();
	} else {
		var account = sessionStorage.getItem("account");
		if (account == null) {
			return next("/");
		} else {
			next();
		}
	}
});

3.前端存储用户信息:在生命周期函数中储存账号account

mounted() {
			this.account = sessionStorage.getItem("account");
}

4.在main组件中显示用户账号:在Main组件中的mounted()中存储账号信息并在页面显示管理员账号(双向绑定)。

六、在前端验证用户是否登录

如果没有登录就不能访问/main页面,仍停留到login登录页面;在前端router中index.js添加路由导航守卫,在每次路由跳转时进行判断。

rout.beforeEach((to, from, next) => {
	if (to.path == '/') {//由于自己定义的login组件的地址为“/”
		// 如果用户访问的登录页,nest直接放行
		return next();
	} else {
		var account = sessionStorage.getItem("account");
		if (account == null) {
			return next("/");
		} else {
			next();
		}
	}
});

七、web会话跟踪

http是无状态的,登录完成后客户端与服务器断开了连接,之后再向后端发送请求,后端就不知道是哪个客户端发送的。

使用会话跟踪:

1.登录 向后端发送账号和密码

2.后端与数据库连接验证账号密码

3.如果账号正确,在后端生成一个token(唯一的一种字符串),把token响应给前端,用JWT生成token。

Base64:将八个bit位一组改为六个bit位一组。

JWT组成的三部分:

第一部分头部(header),第二部分载荷(payload, 用户的信息),第三部分签证(signature)。

步骤:将JWT两个jar包加载到后端里

将生成的token存到admin中(即添加token属性),传到前端去。

生成token的工具类:

/**
 * JWT工具类
 */
public class JWTUtil {

    /**
     * 根据用户id,账号生成token
     * @param u
     * @return
     */
    public static String getToken(Admin u) {
        String token = "";
        try {
            //过期时间 为1970.1.1 0:0:0 至 过期时间  当前的毫秒值 + 有效时间
            Date expireDate = new Date(new Date().getTime() + 20*1000);
            //秘钥及加密算法
            Algorithm algorithm = Algorithm.HMAC256("ZCEQIUBFKSJBFJH2020BQWE");
            //设置头部信息
            Map header = new HashMap<>();
            header.put("typ","JWT");
            header.put("alg","HS256");
            //携带id,账号信息,生成签名
            token = JWT.create()
                    .withHeader(header)
                    .withClaim("id",u.getId())
                    .withClaim("account",u.getAccount())
                    .withExpiresAt(expireDate)
                    .sign(algorithm);
        }catch (Exception e){
            e.printStackTrace();
            return  null;
        }
        return token;
    }

    /**
     * 验证token是否有效
     * @param token
     * @return
     */
    public static boolean verify(String token){
        try {
            //验签
            Algorithm algorithm = Algorithm.HMAC256("ZCEQIUBFKSJBFJH2020BQWE");
            JWTVerifier verifier = JWT.require(algorithm).build();
            DecodedJWT jwt = verifier.verify(token);
            return true;
        } catch (Exception e) {//当传过来的token如果有问题,抛出异常
            return false;
        }
    }

    /**
     * 获得token 中playload部分数据,按需使用
     * @param token
     * @return
     */
    public static DecodedJWT getTokenInfo(String token){
        return JWT.require(Algorithm.HMAC256("ZCEQIUBFKSJBFJH2020BQWE")).build().verify(token);
    }

}

4.前端存储token:sessionStorage.setItem("adminToken", resp.data.data.token);

5.之后每次请求,都将token携带者向后端发送。

6.后端的java对请求中的token进行解析验证。

写一个过滤器将每次拿到的token进行验证。

public class AdminTokenFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("token验证过滤器");
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        String adminToken = request.getHeader("adminToken");
        boolean verify = JWTUtil.verify(adminToken);
        if (verify){//token验证没有问题
            filterChain.doFilter(servletRequest,servletResponse);//继续向后执行
        }else {//token验证失败,向前端响应
            servletResponse.setContentType("text/html;charset=utf-8");
            PrintWriter printWriter = servletResponse.getWriter();

            CommonResult commonResult = new CommonResult(401,"token验证失败,请重新登录");
            ObjectMapper objectMapper = new ObjectMapper();
            String json = objectMapper.writeValueAsString(commonResult);
            printWriter.print(json);
        }
    }
}

八、请求拦截器和响应拦截器

在main.js中配置两个拦截器

请求拦截器:每发送一次http请求,都会执行此拦截器

axios.interceptors.request.use(config => {
	//为请求头对象,添加 Token 验证的 token 字段
	config.headers.adminToken = window.sessionStorage.getItem('adminToken');
	return config;
})

响应拦截器:

axios.interceptors.response.use((resp) => {
	if(resp.data.code == 500){
		ElementUI.Message({
			message:resp.data.message,
			type:"error"
		})
	}
	if(resp.data.code == 401){
		ElementUI.Message({
			message:"token验证失败",
			type:"error"
		})
		router.replace("/");
	}
	return resp;
});

你可能感兴趣的:(vue.js,前端,javeEE,ajax)