1. 你掌握前端的哪些知识?
- vue2
- element-ui
- 了解一些css,js
2. 那你说一下vue中的路由吧?
- vue中的路由是用来设定访问路径的,将路径映射到组件页面上
3. 说一下前端vue页面之间传参的方式?
-
路由查询字符串(我用的)
// 路由定义 { path: '/article', component: article }// 跳转并传参 viewDetails(row) { //现将参数存储let id = row.id;let title =row.titlethis.$router.push({//添加需要传值到那个页面的路径path:'/article',//携带需要传递的参数query:{id:id,title:title,}}) } // 获取参数 loadArticleList() {//接受上级页面传来的id参数let id = this.$route.query.id;console.log(this.$route)console.log("文章id:"+id)}
-
通过事件传值:通过
$emit
触发事件并传值,在目标组件通过$on
监听接收。// 传值页 this.$emit('sendMsg', 'some value')// 目标页 mounted() { this.$on('sendMsg', (value) => {// do something}) }
4. 那前端中父子组件怎么传参?
- Props:父组件通过
props
向子组件传递数据。
// 父组件
<ChildComponent message="some data" />// 子组件
props: ['message']
子组件可以通过this.message
访问props
传递过来的数据。
- 自定义事件:子组件通过$emit触发事件,父组件通过v-on监听子组件事件并获取值。
// 子组件
this.$emit('sendMsg', 'some value')// 父组件
<ChildComponent v-on:sendMsg="getMsg"/>methods: {getMsg(value) {// ...}
}
5. 你说一下前后端交互的请求方法有哪些?分别在什么场景下使用?
- get:获取资源的
- post:创建新的资源
- delete:删除资源
- put:更新/上传资源(单个资源数据完全更新)
- PATCH: 更新/上传资源(单个资源的部分内容)
一般来说,获取信息使用GET,创建和更新使用POST或PUT,删除使用DELETE。POST和PUT的选择依据是是否完全替换资源
6. 说一下Spring MVC的基本流程?
-
用户发送请求到前端控制器(DispatcherSetvlet),
-
前端控制器将读取url查找匹配的hander对象传到处理器映射器(handlerMapping) ,并返回handler对象给前端控制器(DispatcherSetvlet)
-
前端控制器(DispatcherSetvlet)调用处理器适配器,
-
适配器确定处理业务(Controller)
-
Controller调用指定的service处理
-
处理完成后返回modeandview对象(json格式)给前端控制器
-
前端控制器(DispatcherSetvlet)调用视图解析器进行解析
-
视图解析器解析完成后返回view视图
-
将视图传递给前端显示
7. 那事务在MVC哪一层?
在MVC架构中,事务属于Model层。
MVC分三层:
View: 用于展示数据,界面层。
Controller: 用于接收用户输入和处理用户请求,控制层。
Model: 用于业务逻辑和数据处理,模型层。
8. 什么情况下在方法上加事务注解?
- 在方法中包含多个关键业务的操作(转账,交易,出库等),如果某一个操作失败会导致数据不一致,需要进行事务管理,要么都成功,要么都失败
- 当我们需要保证一个业务操作中锁住某些数据时,防止其他线程对数据进行修改,需要使用数据库事务。
- 当一个方法中既有读数据库的操作又有写数据库的操作时,如果读写顺序重要我们也需要事务来保证正确的顺序。
9. Spring管理bean的方式有哪些?
-
@Component:这是Spring中最基本的bean注册方式,它会自动将标识了@Component的类注册为Spring bean。
我们可以使用@Component的衍生注解来进一步定义bean的类型,如:
- @Repository:用于数据访问层(DAO)的bean
- @Service:用于业务逻辑层(service)的bean
- @Controller:用于表现层(MVC控制器)的bean
-
@Bean:这是@Configuration配置类中的方法级别的注解,用于直接注册一个bean。
10. 工厂设计模式你了解吗?
是的,工厂设计模式是一种常用的设计模式。工厂设计模式有以下几个角色:
- 工厂(Factory):工厂类,用于创建产品对象。
- 产品(Product):所创建的产品对象。
- 具体工厂(ConcreteFactory):具体的工厂实现类,用于创建具体的产品对象。
- 具体产品(ConcreteProduct):具体的产品实现类。工厂设计模式有三种类型:
- 简单工厂(Simple Factory):有一个工厂类,直接根据参数创建产品对象。
- 工厂方法(Factory Method):定义一个创建产品对象的工厂接口或抽象类,具体的实现交给子类去实现。
- 抽象工厂(Abstract Factory):用于创建一组相关或相互依赖的对象,提供一个创建一系列产品的接口,而无需指定其具体的类。
举个简单的例子:
简单工厂模式:
public class CarFactory {public Car createCar(String type) {if ("汽车".equals(type)) {return new Car();} else if ("电动车".equals(type)) {return new ElectricCar();}}
}
工厂方法模式:
public interface CarFactory {Car createCar();
}public class CarFactoryImpl1 implements CarFactory {public Car createCar() {return new Car();}
}public class CarFactoryImpl2 implements CarFactory {public Car createCar() {return new ElectricCar();}
}
使用工厂设计模式的主要优点是解耦,使客户端和具体产品之间的依赖关系解耦,客户端不再需要知道如何去创建具体的产品对象。
11. 说一下你知道的设计模式?
- 单例模式
- 代理模式
- 工厂模式
- mvc
12. 线程安全的单例模式代码如何编写?
- 使用同步方法(synchronized )进行同步_懒汉式
- 双重检查锁定(了解不多)
13. 说一下bean的作用域?
- singleton:单例模式,容器初始化时创建bean实例,在整个容器内只有一个实例。
- prototype:原型模式,每次注入或者通过Spring ApplicationContext获取的时候,都会返回一个新的实例。
- request:每次HTTP请求会创建一个新的bean,该作用域仅在WebApplicationContext环境下有效。
- session:每次HTTP Session创建一个新的bean实例,该作用域仅在WebApplicationContext环境下有效。
- application:
ServletContext
初始化时创建一个新的bean实例,该作用域仅在WebApplicationContext环境下有效。
14. mybatis框架sql session factory有什么作用?
- 创建SqlSession对象。SqlSession对象是mybatis中最重要的一个对象,它用于执行SQL语句,提交或回滚事务。
- 配置mybatis,如数据库连接池、事务管理器、映射文件位置等。这些配置信息会在构建SqlSessionFactory对象时指定。
- 维护映射关系。SqlSessionFactory对象会解析映射文件中的所有映射语句,并将它们编译成映射关系,存储在内存中。当执行SQL语句时,mybatis会根据这些映射关系来生成实际执行的SQL语句。
- 事务支持。在打开一个事务后,同一个SqlSessionFactory对象创建的所有SqlSession对象会复用该事务。如果其中一个SqlSession提交或回滚了事务,其他SqlSession都会自动提交或回滚。
- 连接池维护。SqlSessionFactory底层封装了连接池,它可以创建、释放、管理连接池中的连接。SqlSession可以从连接池中获取连接来执行SQL语句。
15. 在实际项目里面会创建几个SqlSessionFactory呢?
通常会创建两个SqlSessionFactory:
- 主SqlSessionFactory: 用于主业务逻辑,连接生产环境数据库,创建大部分Mapper接口。
- 测试SqlSessionFactory: 用于测试环境,连接测试环境数据库,创建少数测试用Mapper接口。
16.在实际项目里面会创建几个SqlSession呢?
- 一个应用级别的 SqlSession,供整个应用使用。这个 SqlSession 的生命周期跟应用一致,一直存在。通常使用
SqlSessionFactory#openSession()
方法获得。 - 一个请求级别的 SqlSession,供一个请求使用。这个 SqlSession 的生命周期跟请求一致,请求结束就关闭。通常使用
SqlSessionFactory#openSession(true)
方法获得,参数 true 表示自动提交事务。 - 一个线程级别的 SqlSession,供一个线程使用。这个 SqlSession 的生命周期跟线程一致,线程结束就关闭。通常也使用
SqlSessionFactory#openSession()
方法获得。 - 一个作用域级别的 SqlSession,根据需要定义生命周期。可以使用
SqlSessionFactory#openSession(ExecutorType, boolean)
方法获得,根据 ExecutorType 的种类来决定生命周期的长短。
17. mysql性能优化?
- 开启缓存查询
- 增加索引查询
- 在业务层做数据校验和容错处理,避免无效数据进入 数据库
18. 遍历hashmap的几种方式?
- 使用 Map.keySet() 遍历 key:
java
Map<String, Integer> map = new HashMap<>();
for (String key : map.keySet()) {Integer value = map.get(key);// do something
}
- 使用 Map.entrySet() 遍历 key 和 value:
java
for (Map.Entry<String, Integer> entry : map.entrySet()) {String key = entry.getKey();Integer value = entry.getValue();// do something
}
- 使用 Map.forEach() 和 lambda 表达式遍历:
java
map.forEach((key, value) -> {// do something
});
19. 基于spring security单点登录的流程?
20. 在业务中,用户在前端第一次输入密码后,有没有对密码进行加密?
有,在前端用户点击提交时间,会将密码进行加密传输到后端
21. 密码从前端提交到后端的途中如何加密?
- 前端使用 JS 加密,后端使用相同的算法解密:
// 前端加密
let pwd = '123456';
let encryptPwd = md5(pwd); // md5 哈希// 发送 encryptPwd 到后端// 后端解密
let decryptPwd = md5('123456');
if (encryptPwd === decryptPwd) {// 密码验证成功
}
缺点是如果加密算法泄露,就失去意义。
- 前端使用对称加密,后端使用非对称加密解密:
// 前端使用 AES 和密钥加密
let pwd = '123456';
let key = 'secret key';
let encryptPwd = AES.encrypt(pwd, key); // 发送 encryptPwd 到后端// 后端使用 RSA 私钥解密 AES 密文
let decryptPwd = RSA.decrypt(encryptPwd, privateKey);
if (decryptPwd === '123456') {// 密码验证成功
}
这种方式较为安全,但前端需要管理好密钥。
22. 过滤器和拦截器的区别?
过滤器和拦截器都是AOP(面向切面编程)中的重要概念。
但它们之间有一定的区别:
过滤器(Filter):
- 主要用于对请求做预处理和后处理。比如登陆校验,编码转换等。
- 过滤器可以访问请求和响应。可以修改请求头和响应头及响应体。
- 过滤器的执行顺序由 web.xml 中的配置决定。
拦截器(Interceptor):
- 拦截器主要用于拦截控制器方法的执行。比如权限校验,日志记录等。
- 拦截器可以访问控制器方法的请求和响应。可以修改请求头和响应头及响应体。
- 拦截器的执行顺序由拦截器类的 Order 注解或实现接口的 getOrder() 方法决定。
- 拦截器只会拦截控制器方法的执行,而过滤器可以拦截所有请求。
所以总体来说,过滤器的功能更广,拦截器更加强大,主要是因为拦截器可以访问控制器上下文等WEB框架的上下文信息。
23. Spring如何注册拦截器?
在Spring中,拦截器可以通过两种方式注册:
- 通过WebMvcConfigurerAdapter注册
这是在Springboot框架下注册拦截器的推荐方式。你需要创建一个配置类,继承WebMvcConfigurerAdapter,然后重写addInterceptors方法:
@Configuration
public class InterceptorConfig extends WebMvcConfigurerAdapter {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");}
}
- 在Spring MVC的xml配置文件中注册
在Spring MVC项目中,你需要在springmvc-servlet.xml配置文件中注册拦截器:
<mvc:interceptors><mvc:interceptor><mvc:mapping path="/**"/><bean class="cn.myweb.interceptor.MyInterceptor"/> </mvc:interceptor>
</mvc:interceptors>
另外,拦截器的执行顺序是由其注册的顺序决定的,注册在前的拦截器会先被执行。
拦截器方法主要有三个:- preHandle:controller方法执行前调用,若返回false,则不执行controller方法。
- postHandle:controller方法执行后调用。
- afterCompletion:响应输出流输出后调用。
以上的面试均为真实面试经历,解答为个人立即以及整合ChatGPT的答案,如有不正确的,或者不足的欢迎补充~