权限系统:
1、前端:vue + elementui + axios + css + html
2、后端:springboot + mybatis-plus + nybatis + druid + shiro + swagger2 + redis
1、前端界面及按钮事件实现
1.1 登录页面的构建
1.1.1 Login.vue文件
<template>
<div id="aps">
<div id="con">
<!-- 头像 -->
<div class="avatar_box">
<el-image :src="avatar" style="border-radius: 50%;width: 100%;height: 100%;">
<div slot="placeholder" class="image-slot" >
加载中<span class="dot">...</span>
</div>
</el-image>
</div>
<el-form :model="loginForm" :rules="rules" ref="loginForm" class="login-ruleForm">
<el-form-item label="账号" prop="username">
<el-input v-model="loginForm.username" style="width: 200px;"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input type="password" v-model="loginForm.password" style="width: 200px;"></el-input>
</el-form-item>
<el-form-item style="margin-left: 0px; text-align: center">
<el-button type="primary" size="big">登录</el-button>
<!--<el-button @click="register" size="small">注册</el-button>-->
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
export default {
name: "Login",
data() {
return {
avatar:"",
loginForm: {
username:"",
password:""
},
rules: {
username: [
{required: true, message: '请输入账号名称', trigger: 'blur'}
],
password: [
{required: true, message: '请输入密码', trigger: 'blur'}
]
},
registerFormVisible: false,
registerForm:{},
}
},
methods: {
}
}
</script>
<style>
html, body {
height: 100%;
}
body {
margin: 0px;
overflow-x: hidden;
}
#con{
border: 1px solid gray;
border-radius: 10px;
width: 400px;
height: 280px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
padding: 20px;
text-align: center;
background: white;
opacity:0.8;
}
#aps{
width: 100%;
height: 100%;
background-image: url("../assets/images/background3.jpg");
background-size: 100% 100%;
background-position: center center;
overflow: auto;
background-repeat: no-repeat;
position: fixed;
line-height: 100%;
}
#con>.avatar_box{
height: 100px;
width: 100px;
border: 1px solid #eee;
border-radius: 50%;
padding: 10px;
box-shadow: 0 0 10px #ddd;
position: absolute;
left: 50%;
transform: translate(-50%, -50%);
background-color: #fff;
}
.login-ruleForm {
position: absolute;
bottom: 0;
width: 100%;
padding: 0 50px;
box-sizing: border-box;
}
</style>
1.1.2 App.vue
<template>
<div id="app">
<router-view/>
</div>
</template>
<script>
export default {
name: 'app',
components: {
}
}
</script>
<style>
</style>
1.1.3 router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Login from '../views/Login.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
redirect: '/login'
},
{
path: '/login',
name: 'Login',
component: Login
}
]
const router = new VueRouter({
routes
})
export default router
1.2 登录按钮事件
如果想在vue工程中使用axios进行异步请求,则需要在main.js中导入axios [1]//导入axios import axios from "axios"; [2]//把axios挂载到vue对象中,以后在vue中如果使用axios直接可以用$http名称 Vue.prototype.$http=axios
1.2.1 main.js文件
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import './plugins/element.js'
//导入axios
import axios from "axios";
Vue.config.productionTip = false
//把axios挂载到vue对象中,以后在vue中如果使用axios直接可以使用$http名称
Vue.prototype.$http = axios
new Vue({
router,
render: h => h(App)
}).$mount('#app')
1.2.2 Login.vue文件
在Login.vue文件中点击登录按钮,向后台服务器发送axios异步请求
methods: {
login(){
//表单校验
this.$refs['loginForm'].validate((valid)=>{
if (valid){
//url:后端登录接口的路径
this.$http.post("http://localhost:8080/login",this.loginForm).then(result=>{
console.log(result)
})
}
})
}
}
2、后端登录接口
2.1 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.12.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.gjx</groupId>
<artifactId>springboot-vue</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-vue</name>
<description>springboot-vue</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--引入swagger的启动依赖-->
<dependency>
<groupId>com.spring4all</groupId>
<artifactId>swagger-spring-boot-starter</artifactId>
<version>1.9.1.RELEASE</version>
</dependency>
<!--引入swagger的图形界面-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>1.7.8</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<!--代码生成器-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
2.2 mybatis-plus代码生成器
public class CodeGenerator {
public static void main(String[] args) {
FastAutoGenerator.create("jdbc:mysql://192.168.1.29:3306/acl_permission?serverTimezone=Asia/Shanghai", "root", "990412")
.globalConfig(builder -> {
builder.author("gjx") // 设置作者
.enableSwagger() // 开启 swagger 模式
.fileOverride() // 覆盖已生成文件
.outputDir(".\\src\\main\\java"); // 指定输出目录
})
.packageConfig(builder -> {
builder.parent("com") // 设置父包名
.moduleName("gjx") // 设置父包模块名
.pathInfo(Collections.singletonMap(OutputFile.xml, ".\\src\\main\\resources\\mapper\\")); // 设置mapperXml生成路径
})
.strategyConfig(builder -> {
builder.addInclude("acl_permission","acl_role","acl_user") // 设置需要生成的表名
.addTablePrefix("acl_"); // 设置过滤表前缀
})
.templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
.execute();
}
}
2.3 配置application文件
server.port=8081
# 配置mysql数据源
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://192.168.1.29:3306/acl_permission?serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=990412
# mybatis mapper映射文件的路径
mybatis.mapper-locations=classpath:mapper/*.xml
# mybatis-plus的日志文件stdout
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
2.4 前端传递的参数接收类vo包下
2.5 接口
@RestController
public class LoginController {
@Autowired
private IUserService iUserService;
@PostMapping("/login")
public CommonResult login(@RequestBody LoginVO loginVO){
User login = iUserService.login(loginVO);
if (login!=null){
return new CommonResult(2000,"登录成功",null);
}
return new CommonResult(5000,"登录失败",null);
}
}
2.6 使用swagger2进行接口测试
@Configuration
public class SwaggerConfig {
@Autowired
Docket docket;
@Bean
public Docket docket(){
Docket docket = new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.gjx.controller"))
.build();
return docket;
}
private ApiInfo apiInfo(){
Contact DEFAULT_CONTACT = new Contact("dumpling", "https://taobao.com", "1983275549@qq.com");
ApiInfo apiInfo = new ApiInfo("dumpling的接口文档", "关于Student表的一些基本操作", "1.0", "http://192.168.1.29:8080/",
DEFAULT_CONTACT, "Apache 2.0", "http://192.168.1.29:8080/", new ArrayList<VendorExtension>());
return apiInfo;
}
}
测试
3、前端调用后端登录接口
我们会发现报了不支持跨域请求的错误
当使用异步请求从一个网址访问另一个网址时可能会出现跨域问题。 前提: 1. 必须为异步请求 2. 当端口号或协议或ip不同时则会出现跨域
什么是跨域呢?
前端发起请求的域与该请求指向的资源所在的域不一样,凡是发送请求的url的 协议、域名、端口号三者之间任意一者与当前页面地址不同的请求。这里的域指的是这样的一个概念:我们认为若协议 + 域名 + 端口号均相同,那么就是同域。
出现了两个请求: 有一个请求的方式为: OPTIONS 和真实的请求方式
OPTIONS先头部队。---探视后台有没有解决跨域。
解决方法:
1.前端解决
2.后端解决---->这里也有几种方式:
【1】可以借助nginx.
【2】在代码中解决
在控制层接口上添加@CrossOrigin ,不过每一个controller文件都许哟啊加上这个注解
这个注解的一些属性
(origins = {"192.168.0.111:8080","192.168.0.120:8081"},allowedHeaders="运行哪些请求头跨域",methods={"GET","POST"})
origins: 允许哪些域可以跨域访问我这个接口 allowedHeaders:允许哪些请求头信息跨域 methods: 允许哪些请求方式跨域
设置一个全局跨域配置类。
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;
@Configuration
public class CorsConfig {
// 当前跨域请求最大有效时长。这里默认1天
private static final long MAX_AGE = 24 * 60 * 60;
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("*"); // 1 设置访问源地址
corsConfiguration.addAllowedHeader("*"); // 2 设置访问源请求头
corsConfiguration.addAllowedMethod("*"); // 3 设置访问源请求方法
corsConfiguration.setMaxAge(MAX_AGE);
source.registerCorsConfiguration("/**", corsConfiguration); // 4 对接口配置跨域设置
return new CorsFilter(source);
}
}
这个配置类和上面的@CrossOrigin注解两者只能选其一。
4、登录成功后前端路由跳转
5、将用户会话信息存储在redis中
上面咱们写的登录,后端没有保存数据 前端也没有拿到数据进行保存
5.1 修改登录的接口
pom.xml文件
<!--引入jedis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
配置文件
#redis数据库配置
spring.redis.host=localhost
spring.redis.port=6379
@RestController
@Api("登录的接口类")
//@CrossOrigin
public class LoginController {
@Autowired
private IUserService iUserService;
@Autowired
private RedisTemplate redisTemplate;
@PostMapping("/login")
@ApiOperation("登录接口")
public CommonResult login(@RequestBody LoginVO loginVO){
User login = iUserService.login(loginVO);
if (login!=null){
String token = UUID.randomUUID().toString();
ValueOperations forValue = redisTemplate.opsForValue();
forValue.set(token,login,24, TimeUnit.HOURS);
return new CommonResult(2000,"登录成功",token);
}
return new CommonResult(5000,"登录失败",null);
}
}
5.2 修改前端登录方法
后面每次请求都可以携带该token,每次请求都得要人为添加参数token, 我们可以使用axios得请求拦截器。
在登录成功之后,使用一个按钮测试token是否在请求头中
然后观察后台能否获取token