管理系统搭建一般步骤(会话跟踪路由导航守卫响应拦截器)
- 人工智能
- 2025-08-16 22:18:02

1,vue-cli进行项目搭建
2,使用ELement-UI
3,使用vue组件路由
4,点击登录,向后端进行账号密码比对
三种情况:
密码有误
服务器忙
密码正确。
具体步骤:
首先写好前端一个大体框架,然后点击登录按钮时触发的函数,还有使用v-model对数据进行双向绑定。
<template> <!-- 一个组件中只能有一个根标签--> <div class="login_container"> <!-- 登录盒子--> <div class="login_box"> <!-- 头像盒子--> <div class="img_box"> <img src="./assets/logo.png" /> </div> <div style="padding: 100px 30px 30px 0px;"> <el-form label-width="80px"> <el-form-item label="账号"> <el-input v-model="from.account"></el-input> </el-form-item> <el-form-item label="密码"> <el-input type="password" v-model="from.password"></el-input> </el-form-item> <el-form-item> <el-button type="primary" round @click="login()">登录</el-button> <el-button>取消</el-button> </el-form-item> </el-form> </div> </div> </div> </template>其次就是js代码:这是vue框架所以格式是按照vue框架给定的来的。这段代码主要作用就是,前端传给后端账号密码后,后端给前端的响应,前端对响应做出判断,通过状态码做出判断 。
<script> export default { data() { return { from: { account: "adele", password: "12345678" } } }, methods: { login() { this.$http.post("LoginServlet", jsonToString(this.from)).then(resp => { if (resp.data.code == 201) { this.$message({ message: resp.data.message, type: 'warning' }); } else if (resp.data.code == 200) { this.$message({ message: resp.data.message, type: 'success' }); sessionStorage.setItem("account", resp.data.data.account); sessionStorage.setItem("userToken", resp.data.data.token); this.$router.push("/main"); //在js中进行路由导航 } }) } }, } //将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); } </script>由于后端
5,接下来就是后端:
在写后端之前需要在数据库中创建一个管理员的表,代表登录人信息,因为后端需要和数据库进行比对,如果数据库中存在当前登录的信息才可以进入主页面。
这是登录的servlet,读入流,调用dao的函数进行账号密码比对,通过比对结果向前端传入数据。
由于json跨平台兼容,数据体积小等优点,所以我们通过json格式化java对象传给前端。
package com.ffyc.webserver.servlet; import com.fasterxml.jackson.databind.ObjectMapper; import com.ffyc.webserver.Models.CommonData; import com.ffyc.webserver.dao.LoginDao; import com.ffyc.webserver.Models.User; import com.ffyc.webserver.util.JWTUtil; 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; import java.sql.SQLException; public class LoginServlet extends HttpServlet { private LoginDao dao=new LoginDao(); // @Override // protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // // } // @Override // protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // String account=req.getParameter("account");//接收请求中我们自己提交的数据 // User user=new User("adele","123456789"); // ObjectMapper objectMapper=new ObjectMapper(); // String stu=objectMapper.writeValueAsString(user); // resp.getWriter().print(stu); // System.out.println(objectMapper.writeValueAsString(user)); // if(account.equals("admin")) // { // resp.getWriter().print("账号已注册"); // } // else // { // resp.getWriter().print("账号未注册"); // } // } @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); System.out.println(password); PrintWriter printWriter=resp.getWriter(); User user= null; CommonData commonData=null; try { user = dao.logindao(account,password); if(user==null) { commonData=new CommonData(201,"账号或密码输入有误,请重新输入!"); } else { user.setToken(JWTUtil.getToken(user)); commonData=new CommonData(200,user,"登录成功"); System.out.println(user.getToken()); } } catch (Exception throwables) { commonData=new CommonData(500,"服务器忙...请稍后重试!"); } ObjectMapper objectMapper=new ObjectMapper(); String json=objectMapper.writeValueAsString(commonData); printWriter.print(json); } }然后就是dao层的调用了,因为只要是对数据库进行增删改查操作时,我们都需要调用一次数据库,所以,将数据库连接打包成一个类,每当进行操作,调用该类即可。
DBUtil.java
package com.ffyc.webserver.util; import java.sql.*; public class DButils { static { try { Class.forName("com.mysql.cj.jdbc.Driver"); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { String url = "jdbc:mysql://127.0.0.1:3306/userdb?serverTimezone=Asia/Shanghai"; Connection connection = DriverManager.getConnection(url, "root", "123456"); return connection; } public static void close(ResultSet resultSet, Statement statement, Connection connection) throws SQLException { if (resultSet != null) { resultSet.close(); } if (statement != null) { statement.close(); } if (connection != null) { connection.close(); } } }然后再写一个登录对账号密码验证的dao:使用sql语言调用数据库进行查询,最后将查询到数据以对象形式返回。如果对象为空代表未在数据库查到当前账号,说明账号或密码有误,不为空则说明登录成功。
package com.ffyc.webserver.dao; import com.ffyc.webserver.Models.User; import com.ffyc.webserver.util.DButils; import java.sql.*; public class LoginDao { public User logindao(String account, String password) throws SQLException { String sql="select * from user where account=? and password=?"; Connection connection=DButils.getConnection(); PreparedStatement preparedStatement= connection.prepareStatement(sql); preparedStatement.setObject(1,account); preparedStatement.setObject(2,password); ResultSet resultSet=preparedStatement.executeQuery(); User user=null; if(resultSet.next()) { user=new User(); String psw=resultSet.getString("password"); user.setAccount(account); user.setPassword(psw); } DButils.close(resultSet,preparedStatement,connection); return user; } }因为要以对象形式返回数据,所以需要创建登录者信息类:
package com.ffyc.webserver.Models; public class User { String id; String account; String password; String token; public String getToken() { return this.token; } public void setToken(String token) { this.token = token; } public void setAccount(String account) { this.account = account; } public void setPassword(String password) { this.password = password; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getAccount() { return account; } public String getPassword() { return password; } }最后,不要忘记配置当前servlet:
<servlet> <servlet-name>Login</servlet-name> <servlet-class>com.ffyc.webserver.servlet.LoginServlet</servlet-class> <!-- <load-on-startup>0</load-on-startup>--> </servlet> <servlet-mapping> <servlet-name>Login</servlet-name> <url-pattern>/LoginServlet</url-pattern> </servlet-mapping>这样,一个简单的登录就完成了。
6,我们发现,类似于状态码为500的公共拦截码如果每次都写一遍很费时间,所以在前端为axios配置响应拦截器,将500这种公共拦截码进行拦截。
import axios from 'axios'; //设置访问后台服务器地址 axios.defaults.baseURL = "http://localhost:8088/webServer/"; //将 axios 挂载到 vue 全局对象中,使用 this 可以直接访问 //axios 请求拦截 每次向后端发送 axios.interceptors.request.use(config => { //为请求头对象,添加 Token 验证的 token 字段 config.headers.userToken = window.sessionStorage.getItem('userToken'); return config; }) axios.interceptors.response.use((resp) => { //正常响应拦截 if (resp.data.code == 500) { ElementUI.Message({ message: resp.data.message, type: "error" }) } if (resp.data.code == 402) { ElementUI.Message({ message: resp.data.message, type: "error" }) router.replace("/login"); } return resp; }); Vue.prototype.$http = axios;为axios框架配置响应拦截器,一旦后端做出响应,响应器拦截。
7,存在的问题:在登录页面的地址栏输入主页面地址可以直接访问,无需验证账号密码。
解决办法:在登录前判断验证用户是否登录,未登录就不能访问/main。
路由导航守卫:每当发生路由,自动调用此方法。
路由导航守卫是一种在路由导航过程中进行拦截和控制的机制。它允许开发者在用户导航到某个路由之前、之后或在路由发生变化时执行相应的操作。
路由导航守卫可以用于实现诸如身份验证、权限检查、日志记录等功能。通过注册守卫函数,开发者可以在路由导航事件发生时介入,并根据需要执行特定的逻辑。
to:访问组件地址
from:从哪个组件发起的路由
next():放行函数。
写入index.js中:导出路由器对象,并将代码包装在模块中并导出对象
import Vue from 'vue'; import router from 'vue-router'; /* 导入路由 */ /* 导入需要路由的组件 */ import Login from "../Login.vue"; import Main from "../Main.vue"; import student from '../student/student.vue'; import marjor from '../marjor/marjor.vue'; Vue.use(router) /* 定义组件路由 */ var rout = new router({ routes: [{ path: '/', component: Login }, { path: '/login', /* 地址 */ name: 'login', /* 地址名 */ component: Login /* 调用地址 */ }, { path: '/main', component: Main, children: [{ path: "/student", component: student, }, { path: "/marjor", component: marjor }], } ] }); //导出路由对象 rout.beforeEach((to, from, next) => { if (to.path == '/login') { //如果用户访问的登录页, 直接放行 return next(); } else { var account = window.sessionStorage.getItem("account"); if (account == null) { return next("/login"); } else { next(); } } }) export default rout;8, 前端显示用户信息,并实现安全退出。
<script> export default { name: "main", data() { return { account: "" } }, methods: { open() { this.$confirm('此操作将退出当前账号, 是否继续?', '操作提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { this.$message({ type: 'success', message: '账号已退出!', }); sessionStorage.clear(); this.$router.push("/login"); //在js中进行路由导航 }); }, test() { this.$http.get("admin/LoginServlet"); } }, mounted() { this.account = sessionStorage.getItem("account"); } } </script>9,登录成功后,进入管理后台,需要会话跟踪。
由于http请求是无状态的,默认不携带用户信息,所以在一次会话中,需要多次向后端发送请求,我们需要让后端程序知道是谁发送的请求。这个过程称为会话跟踪。
①传统的session会话:登录成功后,在后端生成HttpSession对象。里面可以存储用户信息和id,存储在服务器端,id号响应给前端,前端提交id到后端,查询session对象。(不适合分布式架构)
在分布式架构中,各个子系统通常相互独立且自治,它们可以并行地处理任务,从而提高系统的处理能力。每个子系统可以运行在自己的硬件设备上,也可以共享资源,例如数据库、存储等。通过将负载均衡和故障容错机制引入到系统中,分布式架构可以实现系统的高可用性和容错性。
②token会话:
jwt搭建:
①配置安装jar包;
②创建生成token方法;
③之后每次请求都要发送token(在前端axios中配置拦截器,每次向后端发送)
//axios 请求拦截 每次向后端发送 axios.interceptors.request.use(config => { //为请求头对象,添加 Token 验证的 token 字段 config.headers.userToken = window.sessionStorage.getItem('userToken'); return config; })④每次做出响应之前进行token验证
package com.ffyc.webserver.util; import com.auth0.jwt.JWT; import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.interfaces.DecodedJWT; import com.ffyc.webserver.Models.User; import java.util.Date; import java.util.HashMap; import java.util.Map; /** * JWT工具类 */ public class JWTUtil { /** * 根据用户id,账号生成token * @param u * @return */ public static String getToken(User u) { String token = ""; try { //过期时间 为1970.1.1 0:0:0 至 过期时间 当前的毫秒值 + 有效时间 Date expireDate = new Date(new Date().getTime() + 3600*1000); //秘钥及加密算法 Algorithm algorithm = Algorithm.HMAC256("ZCEQIUBFKSJBFJH2020BQWE"); //设置头部信息 Map<String,Object> 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); } } package com.ffyc.webserver.filter; import com.fasterxml.jackson.databind.ObjectMapper; import com.ffyc.webserver.Models.CommonData; import com.ffyc.webserver.util.JWTUtil; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.io.PrintWriter; public class TokenFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest httpServletRequest=(HttpServletRequest) servletRequest; String userToken = httpServletRequest.getHeader("userToken"); if(JWTUtil.verify(userToken)) { filterChain.doFilter(servletRequest, servletResponse); }else{ PrintWriter printWriter=servletResponse.getWriter(); CommonData commonData=new CommonData(402,"Token认证失败!"); ObjectMapper objectMapper=new ObjectMapper(); String json=objectMapper.writeValueAsString(commonData); printWriter.print(json); } } }会话跟踪实现:
第一次登录成功时,在后端根据管理员信息以及密钥生成的token(字符串),响应给前端,之后每次请求都携带token到后端,后端对token进行验证。
管理系统搭建一般步骤(会话跟踪路由导航守卫响应拦截器)由讯客互联人工智能栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“管理系统搭建一般步骤(会话跟踪路由导航守卫响应拦截器)”