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

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

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

跨域问题处理

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

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

代码如下

java 复制代码
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包

xml 复制代码
<!--        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

java 复制代码
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

js 复制代码
//路由导航守卫,每当前端发生一次路由跳转时,会自动触发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

java 复制代码
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 复制代码
<!-- 一个.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包

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

添加拦截器类

java 复制代码
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

java 复制代码
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/**"); //用户需要拦截过滤地址

	}


}

测试拦截器

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

前端测试方法

js 复制代码
test(){
				this.$http.get("loginCtl/test");
			}

后端测试方法

java 复制代码
@RequestMapping(path = "/test")
    public String test(@RequestBody Admin admin){
        return "success";
    }

清空Token

激活test()方法

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

对应main.js代码如下

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;
});

后端响应

相关推荐
用户8307196840824 小时前
Spring Boot 集成 RabbitMQ :8 个最佳实践,杜绝消息丢失与队列阻塞
spring boot·后端·rabbitmq
Java水解5 小时前
Spring Boot 视图层与模板引擎
spring boot·后端
Java水解5 小时前
一文搞懂 Spring Boot 默认数据库连接池 HikariCP
spring boot·后端
洋洋技术笔记9 小时前
Spring Boot Web MVC配置详解
spring boot·后端
初次攀爬者1 天前
Kafka 基础介绍
spring boot·kafka·消息队列
用户8307196840821 天前
spring ai alibaba + nacos +mcp 实现mcp服务负载均衡调用实战
spring boot·spring·mcp
Java水解1 天前
SpringBoot3全栈开发实战:从入门到精通的完整指南
spring boot·后端
初次攀爬者2 天前
RocketMQ在Spring Boot上的基础使用
java·spring boot·rocketmq
花花无缺2 天前
搞懂@Autowired 与@Resuorce
java·spring boot·后端
Derek_Smart2 天前
从一次 OOM 事故说起:打造生产级的 JVM 健康检查组件
java·jvm·spring boot