搭建前端项目,实现前后端交互
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;
});

后端响应
