SpringBoot/Vue3 - 电子书网站
项目介绍
- 基于SprintBoot/MyBatis/Vue3的电子书管理网站,功能包括身份认证系统 (单点登录),用户管理,电子书管理等.
- 前端是使用 Vue3/AntDesign 开发的单页应用,使用 vue-router 路由与 axios 调用后端请求.
- 使用了Redis + Token来实现简化版的单点登录.
数据库
表结构
- category表 (id, parent, name, sort) → 电子书分类的数据和层级
- user表 (id, login_name, name, password)
- doc表 (id, ebook_id, parent, name, sort, view..) → 某电子书拥有的相关文档数据
- ebook表 (id, name, category, 描述...) → 电子书数据
数据库连接
使用IDEA集成的Database功能进行连接.
连接Localhost
输入Localhost的数据库的账号密码,即可完成连接.
连接云数据库
登录开发
登录
- 前端输入用户名密码
- 校验用户名密码
- 登录成功后,生成token (注意 topken的生成ID,要保证唯一)
- 后端保存
token (redis)={token1: 用户信息1, token2: 用户信息2 ....}
// 雪花算法生成token id
// long or string type 都可以
long token = snowFlake.nextId();
// 保存时效 = 3600s * 24hrs = 1day
redisTemplate.opsForValue().set(token.toString(), userLoginResp, 3600 * 24, TimeUnit.SECONDS);
- 前端保存token,使用vuex + sessionStorage来保存登录信息
校验
- 前端请求时,带上token(放在header)
- 登录拦截器(or AOP),校验token (从redis中获取token,如果命中则有效)
LoginInterceptor
// 从请求的header中获取token
String token = request.getHeader('token');
if (token == null || token.isEmpty()) // 说明token为空
// 从redis中查找token
// redis查找的get()方法对类型有要求,必须一致
Object object = redisTemplate.opsForValue().get(token);
if (object == null) return false; // 没有命中
else return true; // 找到了
- 校验成功则继续后面的业务
- 校验失败则回到登录页面
Token 与 JSON Web Token
Token + redis: token本身无意义,只需要保持唯一性 。可以用md5字符串. JWT: token是有意义的,加密的,包含业务信息与用户信息。不需要用到JWT.
e.g. JWT由3部分组成 = header :
{’alg(加密算法)’: ‘’HS256, ‘typ’: ‘JWT’}
, data:{...}
, signature:{签名}
Q&A
2.1 SpringBoot有哪些优点?
- 快速创建独立运行的Spring项目以及与主流框架集成
- 使用嵌入式的Servlet容器,应用无需打成WAR包
- starters自动依赖与版本控制
- 大量的自动配置,简化开发,也可修改默认值
- 无需配置XML,无代码生成,开箱即用
- 准生产环境的运行时应用监控
- 与云计算的天然集成
2.2 SpringBoot为什么能直接运行?
SpringBoot内置嵌入式的Servlet容器,且有大量的自动配置简化开发,能做到开箱即用,所以可以直接运行
2.3 列一下常见的git命令(你都用过哪些命令)?或具体到某个命令的用法,如:怎么从远程仓库把代码取下来?
git branch 查看本地所有分支
git status 查看当前状态
git commit 提交
git branch -a 查看所有的分支
git branch -r 查看远程所有分支
git commit -am "init" 提交并且加注释
git remote add origin git@192.168.1.119:ndshow
git push origin master 将文件给推到服务器上
git remote show origin 显示远程库origin里的资源
git push origin master:hb-dev 将本地库与服务器上的库进行关联
git checkout --track origin/dev 切换到远程dev分支
git branch -D master develop 删除本地库develop
git checkout -b dev 建立一个新的本地分支dev
git merge origin/dev 将分支dev与当前分支进行合并
git checkout dev 切换到本地dev分支
git remote show 查看远程库
2.4 SVN和Git用起来有什么区别,你推荐哪一个?
1. GIT是分布式的,SVN不是
2. GIT把内容按元数据方式存储,而SVN是按文件
3. GIT分支和SVN的分支不同
4. GIT没有一个全局的版本号,而SVN有
5. GIT的内容完整性要优于SVN
6. 综上所述,我更推荐使用Git来管理
2.5 logback日志级别都有哪些?
默认由低到高 trace < debug < info < warn < error,可以调整输出的日志级别,日志就只会在这个级别和更高级别生效。SpringBoot默认给我们使用的是info级别的,没有指定级别就使用默 认级别的。
2.6 slf4j, logback, log4j是什么关系?
SpringBoot底层使用slf4j+logback的方式进行日志记录,如果使用其他的日志,SpringBoot会把其他的日志实现底层都替换为slf4j。log4j和logback是同一个作者写的日志,不过logback实现了slf4j,slf4j本身是一个日志门面,并不包含具体的实现
2.7 列举出常见的http请求方式
GET、POST、DELETE、PUT等等
2.8 怎么读取自定义的配置项?用什么注解?怎么设置默认值?
1. 如果我们需要读取单个自定义配置项,可以使用@Value注解 。例@Value("${test.hello}"),@Value注解支持SpEL。@Value("${test.hello:TEST}"),加上冒号可以设置默认值
2. 如果我们是写了一个JavaBean来和配置文件进行映射,这时候就需要使用到@ConfigurationProperties注解来绑定配置项,它支持绑定多个属性配置项,支持松散绑定,还支持复杂类型的封装
2.9 bootstrap和application配置有什么区别?
Spring Cloud 构建于 Spring Boot 之上,在 Spring Boot 中有两种上下文,一种是 bootstrap, 另外一种是 application, bootstrap 是应用程序的父上下文,也就是说 bootstrap 加载优先于 applicaton。bootstrap 主要用于从额外的资源来加载配置信息,还可以在本地外部配置文件中解密属性。这两个上下文共用一个环境,它是任何Spring应用程序的外部属性的来源。bootstrap 里面的属性会优先加载,它们默认也不能被本地相同配置覆盖。
2.10 为什么引入SpringBoot内置依赖不需要加版本号?
点开pom.xml中的spring-boot-starter-parent父项目就会发现,里面就指定了内置依赖的版本号,所以我们在导入SpringBoot内置依赖时不需要指定版本号,因为父项目已经帮我们指定了版本号。
3.1 常见的持久层框架有哪些?
主要有 Mybatis, Hibernate 两种持久层框架,前者为半自动,后者为全自动
3.2 什么是半自动?什么是全自动?
半自动的持久层框架有时需要程序员手写一些SQL语句,灵活性高,比如 Mybatis。
全自动的持久层框架不需要程序员手写SQL语句,几乎所有的事情都可以交给框架来做,非常省心省事
3.3 Mybatis和Hibernate有什么区别?
Mybatis:需要程序员手写SQL语句,可以严格控制sql执行性能,灵活度高。但是数据无关性差,如果是多种数据库的话,每种数据库都要编写专门的SQL语句,非常麻烦。
Hibernate:不需要程序员手写SQL语句,数据无关性好,可以适应多数据库类型的项目,但是比起Mybatis执行性能会差一些。
3.4 泛型和Object有什么区别?
泛型和Object在使用上区别不大,但是泛型在使用时不需要做强制类型转换,编译时更安全。如果使用Object类的话,你没法保证返回的类型一定是需要的类型,也许是其它类型 。这时你就会在运行时得到一个类型转换异常(ClassCastException)
3.5 你做过的项目中,有没有用过泛型,怎么使用的?
CommonResp<List> resp = new CommonResp<>();
泛型可以在使用时才指定具体的数据类型,非常方便
5.1 Vue怎么调用后端接口?你一般用什么组件?
使用Axios,npm install axios --save
安装,
//发送get请求
axios.get("http://localhost:8880/ebook/list?name=Vue").then((response) => {
console.log(response);
});
5.2 Vue3的setup方法起什么作用?
初始化方法,组件加载完后初始执行的方法。setup执行的时候界面没有渲染好
5.3 简单谈一谈你对跨域的理解?
来自一个IP端口的页面(vue项目8080端口),要访问另一个IP端口的资源(springboot请求端口8880),就会产生跨域访问。解决方法,跨域配置:
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") //映射请求地址,针对所有接口
.allowedOrigins("*") //允许来源所有
.allowedHeaders(CorsConfiguration.ALL)
.allowedMethods(CorsConfiguration.ALL)
.allowCredentials(true) //允许携带凭证sessionId,cookie
.maxAge(3600);//1小时内不需要再预检(发OPTIONS请求)
}
}
5.4 Vue3实现数据绑定有几种方法
ref():const ebooks = ref();
ebooks.value = response.data.content;
reactive里面放一个对象,自定义属性:
const ebooks1 = reactive({books: []});
ebooks1.books = response.data.content;
...
return {
ebooks,
ebooks2: toRef(ebooks1, "books")
}
5.5 说几个Vue组件生命周期函数
生命周期:组件或界面从加载到销毁的过程 onCreate:渲染前 onMounted:组件加载完毕,界面渲染完毕后执行
5.6 双向数据绑定是什么意思?
当数据发生变化的时候,视图也就发生变化,当视图发生变化的时候,数据也会跟着同步变化
5.7 Vue怎么配置多环境?
增加开发和生产配置文件,放在web根目录下:.env.dev和 .env.prod 自定义参数:VUE_APP_XXX 修改package.json中的编译和启动命令:
"scripts": {
"serve-dev": "vue-cli-service serve --mode dev",
"serve-prod": "vue-cli-service serve --mode prod",
"build-dev": "vue-cli-service build --mode dev",
"build-prod": "vue-cli-service build --mode prod",
"lint": "vue-cli-service lint"
},
5.8 axios拦截器用过吗?能用来做什么?
使用axios拦截器打印请求日志和返回参数 main.ts
/**
* axios拦截器
*/
axios.interceptors.request.use(function (config) {
console.log('请求参数:', config);
return config;
}, error => {
return Promise.reject(error);
});
axios.interceptors.response.use(function (response) {
console.log('返回结果:', response);
return response;
}, error => {
console.log('返回错误:', error);
return Promise.reject(error);
});
5.9 过滤器用过吗?有什么用?
配置过滤器打印接口耗时。 过滤器Filter为J2EE Servlet组件,使用时实现Filter接口,重写其中的doFilter方法,对请求和响应进行统一拦截,
5.10 过滤器能注入类吗?
可以
5.11 过滤器和拦截器有什么区别?
拦截器是Spring框架特有的,用于登录校验,权限校验,请求日志打印。分为preHandle和postHandle,preHandle返回true才会向后执行,还需要增加一个全局配置类 而过滤器只在doFilter方法编写逻辑。 执行顺序是过滤器先于拦截器。过滤器的范围更大,因为它在tomcat容器内,然后再进入到容器内的springboot应用中
5.12 拦截器能注入类吗?
可以,@Component注解将拦截器注成一个 bean。然后使用@Autowired注解将类注入到拦截器
5.13 是否用过AOP?一般用来做什么?
AOP是面向切面编程,采用横向抽取机制,取代传统纵向继承机制,将业务无关的代码解耦,适用于性能监视,操作日志的记录,权限校验等。横向抽取即通过代理向目标方法织入增强方法。
5.14 AOP的切点、切面是什么意思?
Pointcut切点:我们所要对哪些连接点进行拦截的定义,使用execution函数定义切点的方法切入 Advice通知,拦截到方法以后要做的事情。分为前置通知,后置通知、环绕通知等。 织入:动词,将增强应用到目标对象来创建新的代理对象的过程 Aspect切面:切点+通知
5.15 AOP有哪些通知?
前置通知@Before,后置通知@After、环绕通知@Around等。
5.16 AOP能注入类吗?
可以
5.17 过滤器、拦截器、AOP有什么区别?
见上文