面经准备

自我介绍

面试官您好,我叫张露文,现就读于东北大学软件学院研究生三年级,面试的岗位是JAVA工程师。在校期间,我的成绩一直在前5%的位置,多次获得了学习奖学金,读研期间发表一篇EI检索的论文,第二篇SCI论文正在投稿过程中,自身掌握了Java语言的基础知识,熟悉mysql数据库,在最近做的项目《酒店外卖点餐系统》后端的开发中也是使用Java语言编写的,用到了目前主流的开源框架SpringBoot、mybatisplus等等。在闲暇的时间,也会去访问csdn、博客园等这些网站来提高自己的知识量。所以,我相信在以后的工作中我一定会给公司创造更大的价值。很荣幸得到这次的面试机会,以上就是我的自我介绍。

1、说说你觉得做过印象最深的项目

就是那个酒店外卖点餐系统,主要负责了后端的菜品管理,分类管理,员工管理,套餐管理,订单明细,这个项目是以SpringBoot框架进行开发的,使用mybatis-plus进行数据库连接的,用到了maven管理工具,使用restful风格进行开发,在控制层使用了RequestMapping来编写代码,,在业务代码中使用Service注解进行开发,Autowired方式来引入类的。

也对项目进行了优化,

在每一次添加员工或者菜单的时候,需要设置以下四个字段(创建时间,更新时间,创建人,更新人),在每一次更新时,要设置以下两个字段(更新时间,更新人) 而这些代码属于重复部分,可以拿出来,不用反复重写。在mybatisplus中提供了一种方法,公共字段自动填充功能(在插入或更新时为指定的字段赋予相应的值,避免了重复的代码)怎么做的: 自定义元数据对象处理器使用注解@Component,实现MetaObjectHandler 类,重写里面的两个方法insertFill和updateFill。

1
2
3
4
5
6
7
8
9
10
11
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime createTime;

@TableField(fill = FieldFill.UPDATE)
private LocalDateTime updateTime;

@TableField(fill = FieldFill.INSERT)
private Long createUser;

@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;

对于缓存的优化,当用户数量多,系统访问数据库过于频繁时,系统性能下降,用户体验差。因此使用redis进行缓存优化,对于缓存菜品数据。使用菜品分类的id作为键,菜品分类中的菜品作为值,如果查找菜品分类对应的菜品时,先通过键在缓存中查找,有就直接返回,如果没有就从数据库中查找,查找成功后再放入到redis中。

2、遇到什么困难,怎么解决

第一个:

对于 用户可以不登录直接访问后台, 配置了过滤器 用于页面访问控制 对于无法直接访问的资源 要先判断 用户是否登录 登录成功后要把用户id存到threadlocal线程类中(创建一个类) 用于后续用户id获取。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 基于ThreadLocal封装的工具类
*/
public class BaseContext {
private static ThreadLocal<Long> threadLocal = new ThreadLocal<>();

public static void setCurrentId(Long id){
threadLocal.set(id);
}

public static Long getId(){
return threadLocal.get();
}

}

第二个:

在编辑员工,通过id来进行员工信息修改的时候,查询数据库的时候发现,修改不成功。发现页面发送请求的id和数据库中要修改的id后三位不同,通过百度查询,发现js对long类型的数据进行处理时丢失了精度。需要使用对象转换器和Spring MVC的消息转换器。(将服务器给页面响应json数据的时候进行处理,将long类型转换为String字符串)

第三个:

新建菜品的时候,前端发过来的请求包含菜品的口味,但是菜品实体中不包含菜品口味的属性。使用dto进行解决。

3、你在项目中负责的什么模块

image-20220920223102550

4、具体功能讲解

员工管理:新增员工,员工禁用,编辑员工信息,员工信息分页查询

5、数据库怎么设计的

首先进行需求分析,通过需求分析来标识要管理的对象,分析对象要存储的信息,也就是有哪些字段,根据字段来确定是什么类型,以及各个对象之间的联系,创建概念模型,画出e-r图,再创建数据库表的同时也要遵循数据库的三大范式,(第一范式,就是保证数据库表中字段的原子性,就是字段是不可再分的数据单元。第二范式,要满足第一范式,每个表描述的是同一间事情,不能订单表还包含产品编号什么的。第三范式就是要满足第二范式,并且字段和主键是直接相关不能是间接相关)

第一范式:

不良做法如下,“学生”一列有多项信息都合在一起了,不再具有原子性,所以应该分开:

img

实际中,原子性还是比较容易理解的。

修改后:

img

第二范式:

不良做法:

img

这个表虽然满足了第一范式,但是也很明显的感受到它的冗余性,其中学生信息和课程信息是冗余的。

修改后,分为学生信息表、课程信息表、学生学分表:

学生信息表:只代表学生的个人信息,主键使用id以防止重名。

img

课程信息表:这里的主键可以不用id,使用课程名称也可以,不会有重名。

img

学生学分表:学生和课程,确定一个学分,这里学生id和课程id作为联合主键来对应一条成绩。

img

第三范式:

img

以上表既满足第一范式也满足第二范式,非主键字段也完全依赖于主键字段。

但是,院系电话字段,其实是依赖院系字段的。也就是说,院系电话字段是非主键值,而依赖了另一个非主键值-院系。所以就不符合第三范式。

改良:

img

img

image-20220920223219442

6、项目是怎么使用MVC思想

MVC就是将软件进行分层设计和实现,分为,视图层(V),控制层(C),模型层(M)。通过分层可以使程序具有更好的灵活性和扩展性,

https://blog.csdn.net/liuyufeng509/article/details/94588359

M:Model,模型层,指工程中的JavaBean,作用是处理数据

JavaBean分为两类:

  • 一类称为实体类Bean:专门存储业务数据的,如 Student、User 等

  • 一类称为业务处理 Bean:指 Service 或 Dao 对象,专门用于处理业务逻辑和数据访问。

V:View,视图层,指工程中的html或jsp等页面,作用是与用户进行交互,展示数据

C:Controller,控制层,指工程中的servlet,作用是接收请求和响应浏览器

MVC的工作流程: 用户通过视图层发送请求到服务器,在服务器中请求被Controller接收,Controller

调用相应的Model层处理请求,处理完毕将结果返回到Controller,Controller再根据请求处理的结果

找到相应的View视图,渲染数据后最终响应给浏览器

包括java的值引用

java中的值传递:传递对象的副本,即使副本的值改变了,也不会影响源对象,因为值传递的时候是将实参的值拷贝一份给形参。

java中的引用传递:传递的并不是实际的对象,而是对象的引用,外部对引用对象的改变会反应到源对象上(数组、类、接口)

redis锁,

redis能用的的加锁命令分表是INCRSETNXSET

incr:

这种加锁的思路是, key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作进行加一。
然后其它用户在执行 INCR 操作进行加一时,如果返回的数大于 1 ,说明这个锁正在被使用当中。

1
2
3
4
5
6
7
8
1、 客户端A请求服务器获取key的值为1表示获取了锁
2、 客户端B也去请求服务器获取key的值为2表示获取锁失败
3、 客户端A执行代码完成,删除锁
4、 客户端B在等待一段时间后在去请求的时候获取key的值为1表示获取锁成功
5、 客户端B执行代码完成,删除锁

$redis->incr($key);
$redis->expire($key, $ttl); //设置生成时间为1

setnx:

这种加锁的思路是,如果 key 不存在,将 key 设置为 value
如果 key 已存在,则 SETNX 不做任何动作

1
2
3
4
5
6
7
8
1、 客户端A请求服务器设置key的值,如果设置成功就表示加锁成功
2、 客户端B也去请求服务器设置key的值,如果返回失败,那么就代表加锁失败
3、 客户端A执行代码完成,删除锁
4、 客户端B在等待一段时间后在去请求设置key的值,设置成功
5、 客户端B执行代码完成,删除锁

$redis->setNX($key, $value);
$redis->expire($key, $ttl);

set:

1
2
3
4
5
6
7
1、 客户端A请求服务器设置key的值,如果设置成功就表示加锁成功
2、 客户端B也去请求服务器设置key的值,如果返回失败,那么就代表加锁失败
3、 客户端A执行代码完成,删除锁
4、 客户端B在等待一段时间后在去请求设置key的值,设置成功
5、 客户端B执行代码完成,删除锁

$redis->set($key, $value, array('nx', 'ex' => $ttl)); //ex表示秒

过期策略,

redis对于设置过期时间的数据,如果一个键过期了,什么时候被删除,redis使用的是惰性删除和定期删除。

  • 惰性删除:每次获取键时,都要检查键是否过期,如果过期则删除,没有过期则返回改键
  • 定期删除:每隔一段时间,程序对数据库进行一次检查,删除里面过期的键。

spring事务及失效场景,

https://blog.csdn.net/m0_67391120/article/details/126041740

springboot的自动装配,线程安全解决办法,抽奖概率场景设计,

1.期望工作地点是哪里,接不接受去别的地方,第一年需要去北京培训巴拉巴拉,如果接受的话就开始面试

2.自我介绍

3.平时开发有没有做项目,你介绍一下你第一个项目,有没有用到数据库,sql语句怎么写的,写的多不多,用到了什么复合查询

1
insert into student(name,sex,age) values('张三'18'男')
1
delete from student where id=1
1
update student set name = '张三' where id=1
1
select * from student

复合查询:

3.springboot的controller层是干嘛的,

controller层:根据用户提交过来的请求,通过url匹配匹配给不同的接收器,

get和post区别是什么,项目中哪个用的多

第一个区别:

get请求一般是用来获取资源的,

post请求是用来进行增删改操作的,

第二个区别:

get请求将请求参数拼接到url上进行参数传递的

post请求将请求的参数写入到请求正文中传递。(文件上传只能使用post)

参数值比较少的时候,可以选择get。

4.linux项目怎么部属的,镜像文件怎么用的

5.写项目的时候怎么调试的(我说我没遇到什么逻辑上的问题,然后说用swagger测试后端,然后如何处理异常

重点:这个公司真的会问期望薪资和工作地,提前准备好

  • 自我介绍(询问是否有ppt)

  • 询问了一下科研情况

  • Spring IOC和AOP

    IOC:控制反转,把对象创建和对象之间的调用过程,交给 Spring 进行管理,使用 IOC 目的:为了耦合度降低

    AOP:面向切面,不修改源代码进行功能增强

  • Spring xml开发和注解开发具体实现和区别

  • SpringMVC说说

我主要问了一下具体做的业务,和工作城市主要在哪里,还有后面面试的内容

  • 持续时间:30min
  • 22号二面

面经准备
http://example.com/2022/09/16/面经准备/
作者
zlw
发布于
2022年9月16日
许可协议