1. 项目架构
2. 项目搭建
1. 后端搭建环境
1. 创建sport项目
2. 选择依赖
3. 修改maven
File->Setting
4. 删除不需要的文件,修改配置文件
把properties
改为yml
文件
5. 新建TestController
6. TestController编写代码
路径:src/main/java/com/sport/controller/TestController.java
代码:
package com.sport.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @RestController -- @Controller+@ResponseBody
*
*/
@RestController
public class TestController {
@RequestMapping("/hello")
public String test(){
return "你好";
}
}
7. 运行
路径:src/main/java/com/sport/SportApplication.java
访问:http://localhost:8080/hello
2. vue搭建
1. 查看是否安装NODE
同时按下win+r
弹出框,输入cmd
弹出控制台,输入node -v
,出来版本号,说明node环境存在
2. 查看是否安装NPM
输入npm -v
,出来版本号,说明npm 环境存在
3. 查看是否安装VUE
输入vue -V
,出来版本号,说明vue环境存在
4. vui ui 运行
输入vue ui
, 发现没有任何反应。使用管理员身份运行
运行npm install -g @vue/cli
安装 ,报错
下面这个说明是第二次安装,出现如下错误,说是文件已存在。解决办法错误提示也给出来了,如下图所示,加入--force
强制执行一下。
运行npm install -g @vue/cli --force
执行
win+r
弹出框输入cmd
,控制台输入vue ui
自动打开网页路径http://localhost:8001/project/select
5. 创建vue
在springboot根目录下
复制E:\Java\SpringBoot\sport
目录到Vue项目管理器,点击回车
点击 在此创建新项目
配置项目名称,点击下一步
选择预设,下一步
选择功能,下一步
修改配置,点击创建项目
点击创建项目,不报错预设。
当初次创建Vue项目的时候,若出现类似以下的错误:Cannot read property ‘indexOf‘ of undefined
那么这个时候我们就需要用管理员身份安装一个yarn管理器:
npm install -g yarn
创建成功显示
6. 安装依赖
选择依赖点击安装
输入axios
《异步通信,类似Ajax》,选中,安装
继续点击安装,输入elementui
继续安装
7. 启动vue
任务->serve->启动
访问:http://localhost:8081/#/
8080端口被springboot占用
3. 小程序创建
1. 获取小程序APPID
路径:https://mp.weixin.qq.com/wxamp/basicprofile/index?token=1438541308&lang=zh_CN
2. 创建小程序
输入小程序名称和路径以及appid
模板选择
点击确定
3. 前后端交互
webStrom:https://www.jetbrains.com/zh-cn/webstorm/
VS CODE:https://pc.qq.com/detail/16/detail_22856.html
VS CODE 开发vue 引用博客:VS CODE 开发vue 引用博客
1. 使用vscode运行项目
1. 安装扩展
2. 查看package.json
路径:vue-sport\package.json
3. 运行命令
新建终端
运行命令npm run serve
,运行成功,点击地址,即可跳转
2. 刪除掉多余的代码
删除的hello与about相关代码
3. 访问后端代码
1. 模拟页面请求
路径:src\views\HomeView.vue
代码:
<template>
<div class="home">
<img @click="click" alt="Vue logo" src="../assets/logo.png" />
</div>
</template>
<script>
import axios from "axios";
export default {
name: "HomeView",
components: {},
methods: {
click() {
axios
.get("http://localhost:8080/hello")
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
},
},
};
</script>
页面访问发现有跨域问题
2. 解决跨域问题
路径:src/main/java/com/sport/config/WebConfig.java
代码:
package com.sport.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 跨域处理的配置类
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry
//允许访问路径是所有
.addMapping("/**")
//配置请求来源
.allowedOrigins("http://localhost:8081","null")
//允许跨域访问的方法类型
.allowedMethods("GET","POST","DELETE","PUT","OPTION")
//是否允许请求头部信息
.allowCredentials(true)
//最大响应时间,一个小时
.maxAge(3600);
}
}
3. 访问运行测试
重新运行后端
关掉多余端口,重新运行vue,端口为8081
访问:http://localhost:8081/#/
,获取数据成功
4. 后端统一结果返回及前端axios的挂载
1. 后端统一返回结果
1. 创建响应数据处理
路径:src/main/java/com/sport/util/Result.java
代码:
package com.sport.util;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 响应数据处理
*/
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Result {
/**
* 响应给前端的数据是否放成功的标志
*/
private boolean flag;
/*
响应信息
*/
private String message;//消息
/**
* 响应数据
*/
private Object data;//数据
/**
* 响应成功
*
* @param message
* @param data
* @return
*/
public static Result success(String message, Object data) {
return new Result(true, message, data);
}
/**
* 响应失败
*
* @param message
* @param data
* @return
*/
public static Result fail(String message, Object data) {
return new Result(false, message, data);
}
}
2. 创建分页响应数据处理
路径:src/main/java/com/sport/util/PageResult.java
代码:
package com.sport.util;
import lombok.Data;
/**
* 响应数据分页
*/
import java.util.List;
/**
* 分页返回
*/
@AllArgsConstructor
@NoArgsConstructor
@Data
public class PageResult {
/**
* 总记录数
*/
private long total;
/**
* 分页的数据
*/
private List list;
}
3. 创建查询响应数据处理
路径:src/main/java/com/sport/util/QueryInfo.java
代码:
package com.sport.util;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 查询
*/
@AllArgsConstructor
@NoArgsConstructor
@Data
public class QueryInfo {
/**
* 第几页
*/
private Integer pageNumber;
/**
* 一页多少数据
*/
private Integer pageSize;
/**
* 查询的内容
*/
private String queryString;
}
4. 修改控制器代码用于测试返回
路径:src/main/java/com/sport/controller/TestController.java
代码:
package com.sport.controller;
import com.sport.util.Result;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @RestController -- @Controller+@ResponseBody
*/
@RestController
public class TestController {
@RequestMapping("/hello")
public Result test() {
return Result.success("信息返回成功", "你好!");
//return "你好";
}
}
5. 启动测试
重启springboot
重启vue
springboot页面访问路径:http://127.0.0.1:8080/hello
vue页面访问路径:http://localhost:8081/#/
6. 序列化
为什么实现序列化:https://blog.youkuaiyun.com/qq_45464560/article/details/120472154
路径:src/main/java/com/sport/util/Result.java
代码:
package com.sport.util;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 响应数据处理
*/
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Result implements Serializable {
/**
* 响应给前端的数据是否放成功的标志
*/
private boolean flag;
/*
响应信息
*/
private String message;//消息
/**
* 响应数据
*/
private Object data;//数据
/**
* 响应成功
*
* @param message
* @param data
* @return
*/
public static Result success(String message, Object data) {
return new Result(true, message, data);
}
/**
* 响应失败
*
* @param message
* @param data
* @return
*/
public static Result fail(String message, Object data) {
return new Result(false, message, data);
}
}
2. axios的挂载
vue2和vue3的区别:https://blog.youkuaiyun.com/C90283/article/details/123049450
vue3如何挂载并使用axios:https://blog.youkuaiyun.com/weixin_44523860/article/details/116210864
1. 新建挂载
路径:src\utils\ajax.js
代码:
/* eslint-disable prettier/prettier */
import Vue from "vue";
import axios from "axios";
const ajax = axios.create({
baseURL: "http://127.0.0.1:8080",
});
Vue.prototype.$ajax = ajax;
2. main.js引用
路径:src\main.js
代码:
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
//引用挂载
import "@/utils/ajax";
Vue.config.productionTip = false;
new Vue({
router,
store,
render: (h) => h(App),
}).$mount("#app");
3. 页面修改
路径:src\views\HomeView.vue
代码:
<template>
<div class="home">
<img alt="Vue logo" @click="click" src="../assets/logo.png" />
</div>
</template>
<script>
// @ is an alias to /src
// 注释掉引用axios,改用挂载
//import axios from "axios";
export default {
name: "HomeView",
components: {},
methods: {
click() {
// axios//注释掉axios的使用,改用全局自定义挂载
this.$ajax
.get("/hello")
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
},
},
};
</script>
4. 页面测试
访问:http://localhost:8081/#/
5. 后端分页返回+banner显示
1. 后端分页返回
路径:src/main/java/com/sport/util/PageResult.java
代码:
package com.sport.util;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 响应数据分页
*/
import java.io.Serializable;
import java.util.List;
/**
* 分页返回
*/
//该注解用于子类对象之间进行比较的时候 不加该注解的影响
@EqualsAndHashCode(callSuper = true)
@Data
public class PageResult<T> extends Result implements Serializable {
/**
* 总记录数
*/
private long total;
/**
* 分页的数据
*/
private List<T> rows;
public PageResult(long total, List<T> list) {
this.setFlag(true);
this.setMessage("分页查询成功");
this.total = total;
this.rows = list;
}
}
2. banner显示
原始默认
在resources下创建banner.txt文件
Spring Boot自定义启动Banner在线生成工具https://bootschool.net/ascii
将生成的图标拷贝到resource/banner.txt文件下
重新启动springboot效果
修改banner的颜色以及添加版本,作者
路径:src/main/resources/banner.txt
代码:
${AnsiColor.BRIGHT_GREEN}
___ ___
/ -_) / -_)
\___| \___|
_|"""""|_|"""""|
"`-0-0-'"`-0-0-'
:: spring-boot.version :: (${spring-boot.version}) author: (${spring.author})
配置文件定义spring.author
路径:src/main/resources/application.yml
代码:
server:
port: 8080
spring:
author: 'dd'
启动测试
3. 登录模块
整合 Security + JWT
1. 登录页面的创建
1. 删掉home相关的
2. vscode快捷生成vue模板
- 文件->首选项->用户片段 / 设置->用户片段
- 搜索
vue
,选择vue.json
. - 设置快捷键及模板内容
prefix
表示快捷键为vue
,创建vue
文件后,可以在页面输入vue
快捷生成body
中的代码
body
表示快捷键后生成的代码
{
"Print to console": {
"prefix": "vue",
"body": [
"<template>",
" <div>",
" $0",
" </div>",
"</template>",
"",
"<script>",
"",
" export default {",
" name:'',",
" props:[''],",
" data () {",
" return {",
"",
" };",
" },",
"",
" components: {},",
"",
" computed: {},",
"",
" created() {},",
"",
" mounted() {},",
"",
" methods: {},",
"",
" }",
"",
"</script>",
"<style lang='scss' scoped>",
"",
"</style>"
],
"description": "三线码工vue模板"
}
}
4.创建vue
文件,输入vue
,默认第一个就是生成的快捷代码,按下Enter
选择页面自动生成
5. 生成的代码
6. vscode 快捷键生成vue模板无法生效问题
- 注意:
*页面右下角选择语言模式为Vue,要不然不生效
3. warning Delete ␍
prettier/prettier(eslint配置的一些问题)
- 生成vue页面时,eslint报错
- 解决方法
warning Delete␍
prettier/prettier:Delete␍
prettier/prettier报错问题解决引入博客
4. 创建页面
路径:src\views\login.vue
代码:
<template>
<span>登录页面</span>
</template>
<script>
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: "login",
props: [""],
data() {
return {};
},
components: {},
computed: {},
created() {},
mounted() {},
methods: {},
};
</script>
<style lang="scss" scoped></style>
5. 路由添加
路径:src\router\index.js
代码:
import Vue from "vue";
import VueRouter from "vue-router";
// 引入登录路由
import Login from "@/views/login";
Vue.use(VueRouter);
const routes = [
//配置登录路由
{
path: "/login",
component: Login,
},
];
const router = new VueRouter({
routes,
});
export default router;
6. 访问登录页面
访问:http://localhost:8081/#/login
7. 创建表单
Element UI 访问组件网址:https://element.eleme.cn/#/zh-CN/component/form
点击组件->安装->from表单,选择适合自己的,显示代码,复制代码到开发页面
代码复制到<template><div></div></template>
里面,格式报错,移动到报错的下划线,会有弹出框,点击弹出框里面的快速修复,点击最后一个修复。就不在报错
修复成功后的代码
修改代码,添加事件。路径:src\views\login.vue
代码:
<template>
<div>
<div class="form-class">
<img src="../assets/logo.png" alt="" class="login" />
<el-card class="box-card">
<el-form :model="form" :rules="rules" ref="form" label-width="50px">
<el-form-item label="账号" prop="username">
<el-input
type="text"
v-model="form.username"
autocomplete="off"
></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input
type="password"
v-model="form.password"
autocomplete="off"
></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submit">登录</el-button>
<el-button @click="reset">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</div>
</template>
<script>
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: "login",
props: [""],
data() {
return {
//表单对象
form: {},
//表单校验规则
rules: {
//用户名表单校验
username: [
{ required: true, message: "请输入用户名称", trigger: "blur" },
{
min: 2,
max: 20,
message: "长度在 2 到 20 个字符",
trigger: "blur",
},
],
password: [{ required: true, message: "请输入密码", trigger: "blur" }],
},
};
},
//组件
components: {},
computed: {},
//页面加载函数
created() {},
mounted() {},
//存放所有的 方法
methods: {
//登录提交的方法
submit() {
this.$refs.form.validate((valid) => {
if (!valid) {
return this.$message.error("数据校验失败,请检查后提交");
//如果数据校验成功,则向后端发送请求,进行登录
}
});
},
//重置的方法
reset() {
//将整个表单进行重置,并移除效果
this.$refs.form.resetFields();
},
},
};
</script>
<style>
.form-class {
width: 30%;
margin: 200px 500px auto;
}
.login {
width: 100px;
height: 100px;
}
</style>
运行测试 http://localhost:8081/#/login
2. 登录表的创建
1. 创建数据库
drop database if exists `sport`;
create database `sport` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
2. 创建表
/*
Navicat Premium Data Transfer
Source Server : localhost
Source Server Type : MySQL
Source Server Version : 50726
Source Host : localhost:3306
Source Schema : sport
Target Server Type : MySQL
Target Server Version : 50726
File Encoding : 65001
Date: 20/04/2022 14:10:15
*/
-- 创建数据库
-- drop database if exists `sport`;
-- create database `sport` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
-- 以下创建表
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for roles_menus
-- ----------------------------
DROP TABLE IF EXISTS `roles_menus`;
CREATE TABLE `roles_menus` (
`role_id` bigint(20) NULL DEFAULT NULL COMMENT '角色id',
`menu_id` bigint(20) NULL DEFAULT NULL COMMENT '菜单权限id'
) ENGINE = MyISAM CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '角色和菜单的管理信息' ROW_FORMAT = Fixed;
-- ----------------------------
-- Table structure for roles_permission
-- ----------------------------
DROP TABLE IF EXISTS `roles_permission`;
CREATE TABLE `roles_permission` (
`role_id` bigint(20) NULL DEFAULT NULL COMMENT '角色id',
`permission_id` bigint(20) NULL DEFAULT NULL COMMENT '数据权限id'
) ENGINE = MyISAM CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '角色和权限的关联表' ROW_FORMAT = Fixed;
-- ----------------------------
-- Table structure for sys_menu
-- ----------------------------
DROP TABLE IF EXISTS `sys_menu`;
CREATE TABLE `sys_menu` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`path` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '菜单路径',
`icon` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '菜单图标',
`title` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '菜单名称',
`component` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '菜单组件',
`parent_id` bigint(20) NULL DEFAULT NULL COMMENT '父级id',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '菜单' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for sys_permission
-- ----------------------------
DROP TABLE IF EXISTS `sys_permission`;
CREATE TABLE `sys_permission` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`label` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '权限标签',
`code` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '数据权限的标签值',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '权限表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for sys_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`lable` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '角色描述',
`code` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '角色对应的标签值',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '角色表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`username` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '登录名',
`password` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '密码',
`nick_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '昵称',
`sex` tinyint(1) NULL DEFAULT NULL COMMENT '性别(0男,1女,2未知)',
`avatar` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '头像',
`address` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '地址',
`open_id` varchar(100) comment '微信小程序ipenod,每个用户对应一个,且唯一',
`status` tinyint(1) comment '状态,是否禁用',
`admin` tinyint(1) comment '是不是管理员',
`phone_number` varchar(20) comment '电话号码',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for user_roles
-- ----------------------------
DROP TABLE IF EXISTS `user_roles`;
CREATE TABLE `user_roles` (
`user_id` bigint(20) NULL DEFAULT NULL COMMENT '用户id',
`role_id` bigint(20) NULL DEFAULT NULL COMMENT '角色id'
) ENGINE = MyISAM CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户和角色的关联表' ROW_FORMAT = Fixed;
SET FOREIGN_KEY_CHECKS = 1;
3. 添加基本数据
-- 添加基本数据
INSERT INTO `sys_user` VALUES (null, 'admin', '', '管理员', 0, '', '', '', 0, 0, '');
INSERT INTO sys_role (lable,code) VALUES('超级管理员','SUPER_ADMIN'),('管理员','ADMIN'),('普通角色','PT_ROLE');
insert into sys_menu values
(null,'/','','系统管理','home',null),
(null,'system/user','','用户管理','system/user',1),
(null,'system/role','','角色管理','system/role',1),
(null,'system/permission','','权限管理','system/permission',1),
(null,'system/menu','','菜单管理','system/menu',1);
3. 后端链接数据库
- model层 <
entity/pojo
> --》 实体类 - dao层 <
mapper/dao
> --》 映射 - service层 <
service
> --》 服务层 - controller层 <
controller
>–》 控制器
1. 新建登录控制类
路径:src/main/java/com/sport/controller/LoginController.java
代码:
package com.sport.controller;
import com.sport.util.Result;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 登录
* 退出
* 获取当前登录用户的基本信息
* 相关接口
* 登录接口
*/
@RestController
public class LoginController {
@PostMapping("/user/login")
public Result login() {
return null;
}
}
2. pom.xml引入依赖
<dependencies>
<!--web相关-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--lombok:提供get、set、无参,有参构造等-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--引入mysql依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!--引入mybatis依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
3. 添加持久层(映射层)接口类
路径:src/main/java/com/sport/mapper/SysUserMapper.java
代码:
package com.sport.mapper;
import com.sport.entity.SysUser;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/*系统用户相关操作接口*/
@Mapper
public interface SysUserMapper {
/**
* 查询用户信息
* @return
*/
List<SysUser> findAll();
}
4. 添加实体类
路径:src/main/java/com/sport/entity/SysUser.java
代码:
package com.sport.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 用户实体类
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SysUser {
private long id;
private String userName;
private String passWord;
private Integer sex;
private String avatar;
private String address;
private String openId;
private boolean status;
private boolean admin;
private String phoneNumber;
}
5. 添加mapper.xml
路径:src/main/resources/mapper/SysUserMapper.xml
代码:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.sport.mapper.SysUserMapper">
<select id="findAll" resultType="com.sport.entity.SysUser">
SELECT *
FROM sys_user
</select>
</mapper>
6. 添加seveice接口类
路径:src/main/java/com/sport/service/SysUserService.java
代码:
package com.sport.service;
import com.sport.util.Result;
/**
* 用户操作逻辑的接口
*/
public interface SysUserService {
/**
* 获取所有的用户信息
*/
Result findAll();
}
7. 添加seveiceImpl实现类
路径:src/main/java/com/sport/service/impl/SysUserServiceImpl.java
代码:
package com.sport.service.impl;
import com.sport.mapper.SysUserMapper;
import com.sport.service.SysUserService;
import com.sport.util.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
*
*/
@Service
@Slf4j
public class SysUserServiceImpl implements SysUserService {
@Resource
private SysUserMapper userMapper;
@Override
public Result findAll() {
log.info("获取用户信息");
return Result.success("获取用户信息成功", userMapper.findAll());
}
}
8. 配置mysql和mybatis
路径:src/main/resources/application.yml
代码:
server:
port: 8080
# spring配置
spring:
# 配置开发者
author: 'dd'
# 配置项目名称
application:
name: sport
# 配置mysql数据源
datasource:
#用户名
username: root
#密码
password: root
#链接
url: jdbc:mysql://localhost:3306/sport?useUnicode=true&characterEncoding=utf-8&useSSL=true
# 配置驱动类
driver-class-name: com.mysql.jdbc.Driver
# mybatis 配置
mybatis:
# mapper接口找的xml文件
mapper-locations: classpath:mapper/*.xml
#扫描的实体类
type-aliases-package: com.sport.entity
# mybatis内置的配置
configuration:
# sql日志打印
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 开启驼峰命名
map-underscore-to-camel-case: true
9. 修改登录控制类
路径:src/main/java/com/sport/controller/LoginController.java
代码:
package com.sport.controller;
import com.sport.service.SysUserService;
import com.sport.util.Result;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* 登录
* 退出
* 获取当前登录用户的基本信息
* 相关接口
* 登录接口
*/
@RestController
public class LoginController {
@Resource
private SysUserService userService;
@PostMapping("/user/login")
public Result login() {
return userService.findAll();
}
}
10. 测试
访问:http://localhost:8080/user/login
4. 创建SpringSecurity+登录接口编写
1. 创建实体类
1. 菜单实体类
路径:src/main/java/com/sport/entity/SysMenu.java
代码:
package com.sport.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* 菜单
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SysMenu {
//主键
private Long id;
//路径
private String path;
//图标
private String icon;
//标题
private String title;
//组件
private String component;
//子菜单
private List<SysMenu> children;
}
2. 权限实体类
路径:src/main/java/com/sport/entity/SysPermission.java
代码:
package com.sport.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 权限表
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SysPermission {
private Long id;
//标签名称
private String label;
//标签值
private String code ;
}
3. 角色实体类
路径:src/main/java/com/sport/entity/SysRole.java
代码:
package com.sport.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* 角色实体类
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SysRole {
//主键
private long id;
//标签名称
private String label;
//标签值
private String code;
//菜单信息
List<SysMenu> menus;
// 权限信息
List<SysPermission> permissions;
}
2. 引入SpringSecurity
1. pom.xml引入
<!--引入SpringSecurity-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2. 重启测试
启动发现有一串密码
登录http://localhost:8080/hello
发现自动跳转到http://localhost:8080/login
用户名输入:user 密码输入控制台输出的那串密码
跳转访问成功http://localhost:8080/hello
3. 用户实体类实现security的方法
路径:src/main/java/com/sport/entity/SysUser.java
package com.sport.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
/**
* 用户实体类
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
//实现security的方法
public class SysUser implements UserDetails {
private long id;
private String userName;
private String passWord;
private Integer sex;
private String avatar;
private String address;
private String openId;
private boolean status;
private boolean admin;
private String phoneNumber;
/**
* 权限数据
* @return
*/
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
/**
* 获得密码
* @return
*/
@Override
public String getPassword() {
return passWord;
}
/**
* 获得用户名
* @return
*/
@Override
public String getUsername() {
return userName;
}
/**
* 账号是否过期
* @return
*/
@Override
public boolean isAccountNonExpired() {
return false;
}
/**
* 账号是否被锁定
* @return
*/
@Override
public boolean isAccountNonLocked() {
return false;
}
/**
*
* @return
*/
@Override
public boolean isCredentialsNonExpired() {
return false;
}
/**
* 是否被禁用
* @return
*/
@Override
public boolean isEnabled() {
return status;
}
}
4. 新建功能包
当前用于获取前端传来的数据
路径:src/main/java/com/sport/vo/LoginVo.java
代码:
package com.sport.vo;
import lombok.Data;
/**
* 功能性的字段
*/
@Data
public class LoginVo {
private String username;
private String password;
}
5. 控制器创建登录接口
路径:src/main/java/com/sport/controller/LoginController.java
代码:
package com.sport.controller;
import com.sport.service.SysUserService;
import com.sport.util.Result;
import com.sport.vo.LoginVo;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* 登录
* 退出
* 获取当前登录用户的基本信息
* 相关接口
* 登录接口
*/
@RestController
public class LoginController {
@Resource
private SysUserService userService;
/**
* 登录接口
* @param loginVo
* @return
*/
@PostMapping("/login")
public Result login(@RequestBody LoginVo loginVo) {
// return userService.findAll();
//调用登录的接口
return userService.login(loginVo);
}
}
6. 服务层添加登录接口类
路径:src/main/java/com/sport/service/SysUserService.java
代码:
package com.sport.service;
import com.sport.util.Result;
import com.sport.vo.LoginVo;
/**
* 用户操作逻辑的接口
*/
public interface SysUserService {
/**
* 获取所有的用户信息
*/
Result findAll();
/**
* 登录接口
* @param loginVo 登录参数:账号和密码
* @return 返回token,用token获取资源
*/
Result login(LoginVo loginVo);
}
7. 服务层impl类实现登录接口
路径:src/main/java/com/sport/service/impl/SysUserServiceImpl.java
代码:
package com.sport.service.impl;
import com.sport.mapper.SysUserMapper;
import com.sport.service.SysUserService;
import com.sport.util.Result;
import com.sport.vo.LoginVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
/**
*
*/
@Service
@Slf4j
public class SysUserServiceImpl implements SysUserService {
@Resource
private SysUserMapper userMapper;
@Resource
private UserDetailsService userDetailsService;
@Resource
private PasswordEncoder passwordEncoder;
@Value("${jwt.tokenHead}")
private String tokenHead;
@Override
public Result findAll() {
log.info("获取用户信息");
return Result.success("获取用户信息成功", userMapper.findAll());
}
/**
* 实现登录接口
*
* @param loginVo 登录参数:账号和密码
* @return
*/
@Override
public Result login(LoginVo loginVo) {
log.info("1. 开始登录");
UserDetails userDetails = userDetailsService.loadUserByUsername(loginVo.getUsername());
log.info("2. 判断用户是否存在,密码是否正确");
if (null == userDetails || !passwordEncoder.matches(loginVo.getPassword(), userDetails.getPassword())) {
return Result.fail("账号或密码错误,请重新输入",loginVo);
}
log.info("3. 判断账号是否禁用");
if (!userDetails.isEnabled()) {
return Result.fail("该账号已禁用,请联系管理员",loginVo);
}
log.info("4. 登录成功,在security对象中存入登陆者信息");
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
log.info("5. 根据登录信息,获取token");
// 借助jwt 生成token
String token = "";
Map<String, String> map = new HashMap<>(2);
map.put("tokenHead", tokenHead);
map.put("token", token);
return Result.success("成功",map);
}
}
8. 配置jwt
路径:src/main/resources/application.yml
代码:
server:
port: 8080
# spring配置
spring:
# 配置开发者
author: 'dd'
# 配置项目名称
application:
name: sport
# 配置mysql数据源
datasource:
#用户名
username: root
#密码
password: root
#链接
url: jdbc:mysql://localhost:3306/sport?useUnicode=true&characterEncoding=utf-8&useSSL=true
# 配置驱动类
driver-class-name: com.mysql.jdbc.Driver
# mybatis 配置
mybatis:
# mapper接口找的xml文件
mapper-locations: classpath:mapper/*.xml
#扫描的实体类
type-aliases-package: com.sport.entity
# mybatis内置的配置
configuration:
# sql日志打印
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 开启驼峰命名
map-underscore-to-camel-case: true
# jwt 信息
jwt:
#请求头
tokenHeader: Authorization
#签名加盐
secret: sport111
# jwt过期时间
expiration: 1800
# token 头部
tokenHead: 'Bearer '
9. token工具类的编写
1. pom.xml依赖引入 jwt
<!--引入jjwt-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
2. token工具类的编写
路径:src/main/java/com/sport/util/TokenUtil.java
代码:
package com.sport.util;
import io.jsonwebtoken.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* token工具类的编写
*/
public class TokenUtil {
//注入配置文件的值
@Value("${jwt.secret}")
private String secret;
@Value("${jwt.expiration}")
private long expiration;
/**
* 传入用户信息,生成token
*
* @param details
* @return
*/
public String generateToken(UserDetails details) {
Map<String, Object> map = new HashMap<>(2);
// //内容
map.put("username", details.getUsername());
map.put("created", new Date());
return this.generateJwt(map);
}
/**
* 根据荷载信息生成token
* @param map
* @return
*/
private String generateJwt(Map<String, Object> map) {
return Jwts.builder()//生成密文
// 设置信息
.setClaims(map)
//加密密钥
.signWith(SignatureAlgorithm.HS512, secret)
// token保留的时间 当前时间+ 三个小时
.setExpiration(new Date(System.currentTimeMillis() + expiration * 1000))
.compact();//契约
}
/**
* 根据token 获取荷载信息
*
* @param token
* @return
*/
public Claims getTokenBody(String token) {
try {
return Jwts.parser()
.setSigningKey(secret)//解密密钥
.parseClaimsJws(token)
.getBody();//密文
//String name=claims.get("name").toString();//获取内容
} catch (Exception e) {
return null;
}
}
/**
* 根据token信息得到用户名
*
* @param token
* @return
*/
public String getUsernameByToken(String token) {
return (String) this.getTokenBody(token).get("username");
}
/**
* 判断token是否过期
*
* @param token
* @return
*/
public boolean isExpiration(String token) {
return this.getTokenBody(token).getExpiration().before(new Date());
}
/**
* 重新生成token
* @param token
* @return
*/
public String refreshToken(String token) {
Claims claims = this.getTokenBody(token);
claims.setExpiration(new Date());
return this.generateJwt(claims);
}
}
10. 服务层impl类调用token工具类生成token
路径:src/main/java/com/sport/service/impl/SysUserServiceImpl.java
代码:
package com.sport.service.impl;
import com.sport.mapper.SysUserMapper;
import com.sport.service.SysUserService;
import com.sport.util.Result;
import com.sport.util.TokenUtil;
import com.sport.vo.LoginVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
/**
*
*/
@Service
@Slf4j
public class SysUserServiceImpl implements SysUserService {
@Resource
private SysUserMapper userMapper;
//注入security的登录
@Resource
private UserDetailsService userDetailsService;
// 加密算法
@Resource
private PasswordEncoder passwordEncoder;
//配置文件的值
@Value("${jwt.tokenHead}")
private String tokenHead;
// 引入token工具类
@Resource
private TokenUtil tokenUtil;
@Override
public Result findAll() {
log.info("获取用户信息");
return Result.success("获取用户信息成功", userMapper.findAll());
}
/**
* 实现登录接口
*
* @param loginVo 登录参数:账号和密码
* @return
*/
@Override
public Result login(LoginVo loginVo) {
log.info("1. 开始登录");
UserDetails userDetails = userDetailsService.loadUserByUsername(loginVo.getUsername());
log.info("2. 判断用户是否存在,密码是否正确");
if (null == userDetails || !passwordEncoder.matches(loginVo.getPassword(), userDetails.getPassword())) {
return Result.fail("账号或密码错误,请重新输入", loginVo);
}
log.info("3. 判断账号是否禁用");
if (!userDetails.isEnabled()) {
return Result.fail("该账号已禁用,请联系管理员", loginVo);
}
log.info("4. 登录成功,在security对象中存入登陆者信息");
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
log.info("5. 根据登录信息,获取token");
// 借助jwt 生成token
String token = tokenUtil.generateToken(userDetails);
Map<String, String> map = new HashMap<>(2);
map.put("tokenHead", tokenHead);
map.put("token", token);
return Result.success("成功", map);
}
}