SpringBoot学习day2-前后端的交互搭建以及跨域问题、拦截过滤器问题的解决

发布于:2025-06-12 ⋅ 阅读:(21) ⋅ 点赞:(0)

搭建前端项目,实现前后端交互

1.复制之前宿舍管理系统的前端项目 命名为newsweb

跨域问题处理

2.前端发送异步请求,出现跨域问题

image-20250611183339351

在后端创建跨域处理过滤器如下图

image-20250611183415684

代码如下

package org.example.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import java.util.Collections;

/*
* @Configuration注解表明这是一个配置类,可以包含@Bean注解的方法,这些方法将会在Spring容器中注册为Bean。
* */
@Configuration
public class CorsConfig {

    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        //1,允许任何来源
        corsConfiguration.setAllowedOriginPatterns(Collections.singletonList("*"));
        //2,允许任何请求头
        corsConfiguration.addAllowedHeader(CorsConfiguration.ALL);
        //3,允许任何方法
        corsConfiguration.addAllowedMethod(CorsConfiguration.ALL);
        //4,允许凭证
        corsConfiguration.setAllowCredentials(true);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsFilter(source);
    }
}

3.在后端登录成功后,

生成token

导入jwt jar包

<!--        jwt-->
        <!-- https://mvnrepository.com/artifact/com.auth0/java-jwt -->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>4.4.0</version>
        </dependency>

导入JWTUtil

package com.ffyc.ssm.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.ssm.model.Admin;
import org.springframework.stereotype.Component;


import java.util.Date;
import java.util.HashMap;
import java.util.Map;

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

    /**
     * 根据用户id,账号生成token
     * @param
     * @return
     */

    public static String getToken(Admin admin) {
        String token = "";
        try {
            //过期时间 为1970.1.1 0:0:0 至 过期时间  当前的毫秒值 + 有效时间
            Date expireDate = new Date(new Date().getTime() + 10000*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", admin.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);
    }


}

前端对应的代码router

//路由导航守卫,每当前端发生一次路由跳转时,会自动触发beforeEach().
rout.beforeEach((to,from,next)=>{
	if(to.path=='/login'){//如果访问登录组件,不需要做任何判断,直接放行
	     return next();//放行到目标组件
	}else{
		var token =  sessionStorage.getItem("adminToken");
		if(token==null){ //用户信息为空,说明用户没有登录
			return next("/login");
		}else{//说明用户已经登录
			next();
	    }
	}
}

main.js

import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

/* 导入路由 */
import router from './router/index.js'
Vue.use(router);

/* 导入 elementUI*/
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);

//导入axios组件
import axios from 'axios';
//设置后端默认地址
axios.defaults.baseURL="http://127.0.0.1:8080/";
//将axios对象挂载到vue对象上,并为其指定一个别名
Vue.prototype.$http=axios;

//axios 请求拦截, 每当我们使用axios框架向后端发送请求时,都会经过拦截器
axios.interceptors.request.use(config =>{
	//为请求头对象,添加 Token 验证的 token 字段
	config.headers.token = sessionStorage.getItem('adminToken');
	return config;
})

// 添加响应拦截器
axios.interceptors.response.use((resp) =>{//正常响应拦截
		if(resp.data.code==500){
		   ElementUI.Message({message:resp.data.desc,type:"error"});
		}
		if(resp.data.code==401){
			  ElementUI.Message({message:resp.data.desc,type:"error"});
		    router.replace("/login");
		}
		return resp;
});

new Vue({
  render: h => h(App),
  router,
}).$mount('#app')

前端保存用户token,账号

登录界面代码(存储token、accout、password)

<!-- 一个.vue文件是一个组件,可以理解为一个页面,但是和页面不同 
  内容都写在一个template标签中,
  template标签必须有一个根标签
-->
<template>
	 <div class="login_container">
     <!-- <audio ref="audio" :src="require('./assets/m.mp3')" loop autoplay  controls></audio> -->

	     <!-- 登录盒子-->
	     <div class="login_box">
	          <!-- 头像盒子-->
	          <div class="img_box">
	                <img src="./assets/logo.png" />
	          </div>
			<div style="margin-top: 100px; padding-right: 30px;">
				<el-form ref="form"  label-width="80px">
				  <el-form-item label="账号">
				    <el-input v-model="form.account"></el-input>
				  </el-form-item>
				 <el-form-item label="密码">
				   <el-input v-model="form.password" type="password"></el-input>
				 </el-form-item>
				  <el-form-item>
				    <el-button type="primary" @click="login()">登录</el-button>
				    <el-button>取消</el-button>
				  </el-form-item>
				</el-form>
			</div>
	     </div>
	  </div>
</template>

<script>
/* 导出组件,并为组件定义数据,函数,生命周期函数 */
 export default{
	 data(){
		 return{
			form:{
				account:"admin",
				password:"111"
			}
		 }
	 },
	 methods:{
		 login(){
			 if(this.form.account.length==0){
				 this.$message({message: '账号不能为空!',type: 'warning'});
				 return;
			 }
			 if(this.form.password.length==0){
				 this.$message({message: '密码不能为空!',type: 'warning'});
				 return;
			 }
			 //与后端进行交互
			 this.$http.post("loginCtl/login",this.form).then((resp)=>{
				 //根据后端响应回来的结果进行处理resp.data(result对象)
				 if(resp.data.code==200){
					   //前端浏览器中存储用户信息
					   sessionStorage.setItem("adminToken",resp.data.data.adminToken);
					   sessionStorage.setItem("account",resp.data.data.account);
					   sessionStorage.setItem("password",resp.data.data.password);
					   this.$router.push("/main");
				 }else if(resp.data.code==201){
					 this.$message({message: resp.data.desc,type: 'warning'});
					 return;
				 }else{
					 this.$message({message: resp.data.desc,type: 'warning'});
					 return;
				 }
			 });
		 }
	 }
 }
</script>

<style>
  .login_container{
    height: 100vh;
    margin: 0px;
    padding: 0px;
	background-image: url(assets/bg.jpg);
  }

    .login_box{
      width: 450px;
      height: 350px;
      background-color: #fff;
      border-radius: 10px;
      position: absolute;
      left: 50%;
      top: 50%;
      transform: translate(-50%,-50%);
	  opacity: 0.95;
    }

    .img_box{
       width: 130px;
       height: 130px;
       position: absolute;
       left: 50%;
       transform: translate(-50%,-50%);
       background-color: #fff;
       border-radius: 50%;
       padding: 5px;
       border: 1px solid #eee;
    }
    
    .img_box img{
         width: 100%;
         height: 100%;
         border-radius: 50%;
         background-color: #eee;
     }
</style>

在后端搭建管理员token验证的拦截器

jar包

<!--spring中提供的解决跨域问题的过过滤器-->
        <dependency>
            <groupId>com.thetransactioncompany</groupId>
            <artifactId>cors-filter</artifactId>
            <version>2.5</version>
        </dependency>

添加拦截器类

image-20250611192656119

package org.example.interceptor;



import org.example.util.JWTUtil;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;

//定义拦截器
public class AdminTokenInterceptor implements HandlerInterceptor {


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("进入到了拦截器");
          //获得token
         String adminToken  =   request.getHeader("Token");
        System.out.println("token:"+adminToken);

         if(JWTUtil.verify(adminToken)){
             return true; //拦截器中返回true, 请求就会离开拦截器,继续向后执行,到达处理器
         }else{
             response.setContentType("text/html;charset=utf-8");
             PrintWriter writer = response.getWriter();
             writer.write("token验证失败");
             return false;//拦截器中返回false. 不会继续向后执行.  可以在拦截器中向用户做出响应
         }
    }
}

配置拦截器设置WebConfig

image-20250611193307339

package org.example.config;

import org.example.interceptor.AdminTokenInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.*;

@Configuration
public class WebConfig implements WebMvcConfigurer{

	public void addInterceptors(InterceptorRegistry registry) {
		InterceptorRegistration inter =  registry.addInterceptor(new AdminTokenInterceptor());
		inter.addPathPatterns("/**"); //都得进入拦截器
		inter.excludePathPatterns("/loginCtl/login");//放行地址

		inter.addPathPatterns("/user/**"); //用户需要拦截过滤地址

	}


}

测试拦截器

image-20250611194900306

登录进去之后删除Token,点击测试方法

前端测试方法

test(){
				this.$http.get("loginCtl/test");
			}

后端测试方法

@RequestMapping(path = "/test")
    public String test(@RequestBody Admin admin){
        return "success";
    }

清空Token

image-20250611195111291

激活test()方法

image-20250611195144658

响应拦截器,返回到了登录界面

对应main.js代码如下

// 添加响应拦截器
axios.interceptors.response.use((resp) =>{//正常响应拦截
		if(resp.data.code==500){
		   ElementUI.Message({message:resp.data.desc,type:"error"});
		}
		if(resp.data.code==401){
			  ElementUI.Message({message:resp.data.desc,type:"error"});
			//   删除Token、account、password
			  sessionStorage.clear();
		    router.replace("/login");
		}
		return resp;
});

image-20250611195239341

后端响应

image-20250611195251423