先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip1024b (备注Java)
正文
return “index”;
}
/**
- 分页查询文件
*/
@GetMapping(“files/{pageIndex}/{pageSize}”)
@ResponseBody
public List listFilesByPage(@PathVariable int pageIndex, @PathVariable int pageSize) {
return fileService.listFilesByPage(pageIndex, pageSize);
}
/**
- 获取文件片信息
*/
@GetMapping(“files/{id}”)
@ResponseBody
public ResponseEntity serveFile(@RequestParam(“id”) String id) throws UnsupportedEncodingException {
Optional file = fileService.getFileById(id);
if (file.isPresent()) {
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, “attachment; fileName=” + new String(file.get().getName().getBytes(“utf-8”),“ISO-8859-1”))
.header(HttpHeaders.CONTENT_TYPE, “application/octet-stream”)
.header(HttpHeaders.CONTENT_LENGTH, file.get().getSize() + “”).header(“Connection”, “close”)
.body(file.get().getContent().getData());
} else {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(“File was not fount”);
}
}
/**
- 在线显示文件
*/
@GetMapping(“/view”)
@ResponseBody
public ResponseEntity serveFileOnline(@RequestParam(“id”) String id) {
Optional file = fileService.getFileById(id);
if (file.isPresent()) {
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, “fileName=”" + file.get().getName() + “”")
.header(HttpHeaders.CONTENT_TYPE, file.get().getContentType())
.header(HttpHeaders.CONTENT_LENGTH, file.get().getSize() + “”).header(“Connection”, “close”)
.body(file.get().getContent().getData());
} else {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(“File was not fount”);
}
}
/**
- 上传
*/
@PostMapping(“/”)
public String handleFileUpload(@RequestParam(“file”) MultipartFile file, RedirectAttributes redirectAttributes) {
try {
FileModel f = new FileModel(file.getOriginalFilename(), file.getContentType(), file.getSize(),
new Binary(file.getBytes()));
f.setMd5(MD5Util.getMD5(file.getInputStream()));
fileService.saveFile(f);
System.out.println(f);
} catch (IOException | NoSuchAlgorithmException ex) {
ex.printStackTrace();
redirectAttributes.addFlashAttribute(“message”, “Your " + file.getOriginalFilename() + " is wrong!”);
return “redirect:/”;
}
redirectAttributes.addFlashAttribute(“message”,
"You successfully uploaded " + file.getOriginalFilename() + “!”);
return “redirect:/”;
}
/**
- 上传接口
*/
@PostMapping(“/upload”)
@ResponseBody
public ResponseEntity handleFileUpload(@RequestParam(“file”) MultipartFile file) {
FileModel returnFile = null;
try {
FileModel f = new FileModel(file.getOriginalFilename(), file.getContentType(), file.getSize(),
new Binary(file.getBytes()));
f.setMd5(MD5Util.getMD5(file.getInputStream()));
returnFile = fileService.saveFile(f);
String path = “//” + serverAddress + “:” + serverPort + “/view/” + returnFile.getId();
return ResponseEntity.status(HttpStatus.OK).body(path);
} catch (IOException | NoSuchAlgorithmException ex) {
ex.printStackTrace();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ex.getMessage());
}
}
/**
- 删除文件
*/
@GetMapping(“/delete”)
@ResponseBody
public ResponseEntity deleteFile( @RequestParam(“id”) String id) {
try {
fileService.removeFile(id);
return ResponseEntity.status(HttpStatus.OK).body(“DELETE Success!”);
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
}
}
}
1.7、工具类
md5工具类:
public class MD5Util {
/**
- 获取该输入流的MD5值
*/
public static String getMD5(InputStream is) throws NoSuchAlgorithmException, IOException {
StringBuffer md5 = new StringBuffer();
MessageDigest md = MessageDigest.getInstance(“MD5”);
byte[] dataBytes = new byte[1024];
int nread = 0;
while ((nread = is.read(dataBytes)) != -1) {
md.update(dataBytes, 0, nread);
};
byte[] mdbytes = md.digest();
// convert the byte to hex format
for (int i = 0; i < mdbytes.length; i++) {
md5.append(Integer.toString((mdbytes[i] & 0xff) + 0x100, 16).substring(1));
}
return md5.toString();
}
}
1.8、前端页面
前端页面index.html:
文件服务
文件列表
1.9、运行效果
- 上传文件:
- 预览
- 下载
- 删除
在文件的操作过程中,可以通过可视化工具或shell来查看存储在MongoDB中的文件:
- 可以看到,在fileModel集合中存储了我们上传的文件,文件的内容是以二进制的形式存储
Spring Data MongoDB提供了GridFsOperations接口以及相应的实现GridFsTemplate,可以和GridFs交互。
这里在上一个工程的基础上进行改造。
2.1、依赖
和上一个工程相比,这里添加开源工具包hutool的依赖:
cn.hutool
hutool-all
4.5.1
2.2、启动类
@SpringBootApplication
public class SpringbootFileGridfsApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootFileGridfsApplication.class, args);
}
//Tomcat large file upload connection reset
@Bean
public TomcatServletWebServerFactory tomcatEmbedded() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
tomcat.addConnectorCustomizers((TomcatConnectorCustomizer) connector -> {
if ((connector.getProtocolHandler() instanceof AbstractHttp11Protocol<
?>)) {
//-1 means unlimited
((AbstractHttp11Protocol<?>) connector.getProtocolHandler()).setMaxSwallowSize(-1);
}
});
return tomcat;
}
}
TomcatServletWebServerFactory() ⽅法主要是为了解决上传文件较大时出现连接重置的问题,这个异常后台是捕捉不到的:
2.3、配置
- application.properties
MongoDB 配置
连接uri
#spring.data.mongodb.uri=mongodb://test:test@localhost:27017/filetest
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=filetest
spring.data.mongodb.username=test
spring.data.mongodb.password=test
文件上传限制
spring.servlet.multipart.max-file-size=1020MB
spring.servlet.multipart.max-request-size=1020MB
- 配置类
/**
-
@Author 三分恶
-
@Date 2020/1/11
-
@Description
*/
@Configuration
public class MongoConfig {
//获取配置文件中数据库信息
@Value(“${spring.data.mongodb.database}”)
String db;
GridFSBucket用于打开下载流
@Bean
public GridFSBucket getGridFSBucket(MongoClient mongoClient){
MongoDatabase mongoDatabase = mongoClient.getDatabase(db);
GridFSBucket bucket = GridFSBuckets.create(mongoDatabase);
return bucket;
}
}
2.4、实体类
- 文件实体类
/**
-
@Author 三分恶
-
@Date 2020/1/11
-
@Description
*/
@Document
public class FileDocument {
@Id // 主键
private String id;
private String name; // 文件名称
private long size; // 文件大小
private Date uploadDate; // 上传时间
private String md5; // 文件MD5值
private byte[] content; // 文件内容
private String contentType; // 文件类型
private String suffix; // 文件后缀名
private String description; // 文件描述
private String gridfsId; // 大文件管理GridFS的ID
/**
- 省略getter、setter、equales、hashCode、toString方法
*/
}
- 接口结果实体类
**
-
@Author 三分恶
-
@Date 2020/1/11
-
@Description 公用数据返回模型
*/
public class ResponseModel {
public static final String Success = “success”;
public static final String Fail = “fail”;
private String code = “fail”;
private String message = “”;
private String data;
//私有构造函数,此类不允许手动实例化,需要调用getInstance()获取实例
private ResponseModel() {
}
/**
-
返回默认的实例
-
@return
*/
public static ResponseModel getInstance() {
ResponseModel model = new ResponseModel();
model.setCode(ResponseModel.Fail);
return model;
}
/**
*省略getter/setter
*/
}
2.5、服务层
上一个实例里采用MongReposity来操作MongoDB,这里操作MongoDB采用MongoTemplate,操作GridFs采用GridFsTemplate。
/**
-
@Author 三分恶
-
@Date 2020/1/11
-
@Description
*/
@Service
public class FileServiceImpl implements FileService {
@Autowired
private MongoTemplate mongoTemplate;
@Autowired
private GridFsTemplate gridFsTemplate;
@Autowired
private GridFSBucket gridFSBucket;
/**
-
保存文件
-
@param file
-
@return
*/
@Override
public FileDocument saveFile(FileDocument file) {
file = mongoTemplate.save(file);
return file;
}
/**
-
上传文件到Mongodb的GridFs中
-
@param in
-
@param contentType
-
@return
*/
@Override
public String uploadFileToGridFS(InputStream in , String contentType){
String gridfsId = IdUtil.simpleUUID();
//将文件存储进GridFS中
gridFsTemplate.store(in, gridfsId , contentType);
return gridfsId;
}
/**
-
删除文件
-
@param id
*/
@Override
public void removeFile(String id) {
//根据id查询文件
FileDocument fileDocument = mongoTemplate.findById(id , FileDocument.class );
if(fileDocument!=null){
//根据文件ID删除fs.files和fs.chunks中的记录
Query deleteFileQuery = new Query().addCriteria(Criteria.where(“filename”).is(fileDocument.getGridfsId()));
gridFsTemplate.delete(deleteFileQuery);
//删除集合fileDocment中的数据
Query deleteQuery=new Query(Criteria.where(“id”).is(id));
mongoTemplate.remove(deleteQuery,FileDocument.class);
}
}
/**
-
根据id查看文件
-
@param id
-
@return
*/
@Override
public Optional getFileById(String id){
FileDocument fileDocument = mongoTemplate.findById(id , FileDocument.class );
if(fileDocument != null){
Query gridQuery = new Query().addCriteria(Criteria.where(“filename”).is(fileDocument.getGridfsId()));
try {
//根据id查询文件
GridFSFile fsFile = gridFsTemplate.findOne(gridQuery);
//打开流下载对象
GridFSDownloadStream in = gridFSBucket.openDownloadStream(fsFile.getObjectId());
if(in.getGridFSFile().getLength() > 0){
//获取流对象
GridFsResource resource = new GridFsResource(fsFile, in);
//获取数据
fileDocument.setContent(IoUtil.readBytes(resource.getInputStream()));
return Optional.of(fileDocument);
}else {
fileDocument = null;
return Optional.empty();
}
}catch (IOException ex){
ex.printStackTrace();
}
}
return Optional.empty();
}
/**
-
分页列出文件
-
@param pageIndex
-
@param pageSize
-
@return
*/
@Override
public List listFilesByPage(int pageIndex, int pageSize) {
Query query = new Query().with(Sort.by(Sort.Direction.DESC, “uploadDate”));
long skip = (pageIndex -1) * pageSize;
query.skip(skip);
query.limit(pageSize);
Field field = query.fields();
field.exclude(“content”);
List files = mongoTemplate.find(query , FileDocument.class );
return files;
}
}
2.6、控制层
控制层变动不大,主要是调用服务层方法的返回值和参数有变化:
@Controller
public class FileController {
@Autowired
private FileService fileService;
@Value(“${server.address}”)
private String serverAddress;
@Value(“${server.port}”)
private String serverPort;
@RequestMapping(value = “/”)
public String index(Model model) {
// 展示最新二十条数据
model.addAttribute(“files”, fileService.listFilesByPage(0, 20));
return “index”;
}
/**
- 分页查询文件
*/
@GetMapping(“files/{pageIndex}/{pageSize}”)
@ResponseBody
public List listFilesByPage(@PathVariable int pageIndex, @PathVariable int pageSize) {
return fileService.listFilesByPage(pageIndex, pageSize);
}
/**
- 获取文件片信息
*/
@GetMapping(“files/{id}”)
@ResponseBody
public ResponseEntity serveFile(@PathVariable String id) throws UnsupportedEncodingException {
Optional file = fileService.getFileById(id);
if (file.isPresent()) {
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, “attachment; fileName=” + new String(file.get().getName().getBytes(“utf-8”),“ISO-8859-1”))
.header(HttpHeaders.CONTENT_TYPE, “application/octet-stream”)
.header(HttpHeaders.CONTENT_LENGTH, file.get().getSize() + “”).header(“Connection”, “close”)
.body(file.get().getContent());
} else {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(“File was not fount”);
}
}
/**
- 在线显示文件
*/
@GetMapping(“/view”)
@ResponseBody
public ResponseEntity serveFileOnline(@RequestParam(“id”) String id) {
Optional file = fileService.getFileById(id);
if (file.isPresent()) {
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, “fileName=” + file.get().getName())
.header(HttpHeaders.CONTENT_TYPE, file.get().getContentType())
.header(HttpHeaders.CONTENT_LENGTH, file.get().getSize() + “”).header(“Connection”, “close”)
.header(HttpHeaders.CONTENT_LENGTH , file.get().getSize() + “”)
.body(file.get().getContent());
} else {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(“File was not found”);
}
}
/**
- 上传
*/
@PostMapping(“/”)
public String handleFileUpload(@RequestParam(“file”) MultipartFile file, RedirectAttributes redirectAttributes) {
try {
FileDocument fileDocument = new FileDocument();
fileDocument.setName(file.getOriginalFilename());
fileDocument.setSize(file.getSize());
fileDocument.setContentType(file.getContentType());
fileDocument.setUploadDate(new Date());
String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(“.”));
fileDocument.setSuffix(suffix);
fileDocument.setMd5(MD5Util.getMD5(file.getInputStream()));
//将文件存入gridFs
String gridfsId = fileService.uploadFileToGridFS(file.getInputStream() , file.getContentType());
fileDocument.setGridfsId(gridfsId);
fileDocument = fileService.saveFile(fileDocument);
System.out.println(fileDocument);
} catch (IOException | NoSuchAlgorithmException ex) {
ex.printStackTrace();
redirectAttributes.addFlashAttribute(“message”, “Your " + file.getOriginalFilename() + " is wrong!”);
return “redirect:/”;
}
redirectAttributes.addFlashAttribute(“message”,
"You successfully uploaded " + file.getOriginalFilename() + “!”);
return “redirect:/”;
}
/**
- 上传接口
*/
@PostMapping(“/upload”)
@ResponseBody
public ResponseEntity handleFileUpload(@RequestParam(“file”) MultipartFile file) {
FileDocument returnFile = null;
try {
FileDocument fileDocument = new FileDocument();
fileDocument.setName(file.getOriginalFilename());
fileDocument.setSize(file.getSize());
fileDocument.setContentType(file.getContentType());
fileDocument.setUploadDate(new Date());
String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(“.”));
fileDocument.setSuffix(suffix);
fileDocument.setMd5(MD5Util.getMD5(file.getInputStream()));
//将文件存入gridFs
String gridfsId = fileService.uploadFileToGridFS(file.getInputStream() , file.getContentType());
fileDocument.setGridfsId(gridfsId);
returnFile = fileService.saveFile(fileDocument);
String path = “//” + serverAddress + “:” + serverPort + “/view/” + returnFile.getId();
return ResponseEntity.status(HttpStatus.OK).body(path);
} catch (IOException | NoSuchAlgorithmException ex) {
ex.printStackTrace();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ex.getMessage());
}
}
/**
- 删除文件
*/
@GetMapping(“/delete”)
@ResponseBody
public ResponseModel deleteFile( @RequestParam(“id”) String id) {
ResponseModel model = ResponseModel.getInstance();
if(!StrUtil.isEmpty(id)){
fileService.removeFile(id);
model.setCode(ResponseModel.Success);
model.setMessage(“删除成功”);
}else {
model.setMessage(“请传入文件id”);
}
return model;
}
}
- 前端页面没有变动。
2.7、运行效果
- 上传文件
这里我们选择一个比较大的mp4文件
- 预览
预览还存在问题,后台会报错:org.springframework.http.converter.HttpMessageNotWritableException: No converter for [class edu.hpu.domain.ResponseModel] with preset Content-Type ‘video/mp4’
待解决
- 下载
- 删除
在上传和删除数据的过程中,可以通过可视化工具或shell来查看MongoDB中的数据
- fileDocment中的数据:fileDocment是一个普通的集合,对应地以文档的形式存储了FileDocument实例
- fs.files中的数据:文件的元数据
- fs.chunks中的数据:file被切分成若干个chunks,存储了文件的二进制数据
本文为学习笔记类博客,学习资料来源见参考!
【1】:MongoDB GridFS
【3】:MongoDB学习笔记(五) MongoDB文件存取操作
【4】:《MongoDB大数据权威处理指南》
【5】:java文件转二进制
【6】:Java将文件转为字节数组
【7】:java文件下载的几种方式
总结:绘上一张Kakfa架构思维大纲脑图(xmind)
其实关于Kafka,能问的问题实在是太多了,扒了几天,最终筛选出44问:基础篇17问、进阶篇15问、高级篇12问,个个直戳痛点,不知道如果你不着急看答案,又能答出几个呢?
若是对Kafka的知识还回忆不起来,不妨先看我手绘的知识总结脑图(xmind不能上传,文章里用的是图片版)进行整体架构的梳理
梳理了知识,刷完了面试,如若你还想进一步的深入学习解读kafka以及源码,那么接下来的这份《手写“kafka”》将会是个不错的选择。
-
Kafka入门
-
为什么选择Kafka
-
Kafka的安装、管理和配置
-
Kafka的集群
-
第一个Kafka程序
-
Kafka的生产者
-
Kafka的消费者
-
深入理解Kafka
-
可靠的数据传递
-
Spring和Kafka的整合
-
SpringBoot和Kafka的整合
-
Kafka实战之削峰填谷
-
数据管道和流式处理(了解即可)
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
ongoDB中的数据**
- fileDocment中的数据:fileDocment是一个普通的集合,对应地以文档的形式存储了FileDocument实例
- fs.files中的数据:文件的元数据
- fs.chunks中的数据:file被切分成若干个chunks,存储了文件的二进制数据
本文为学习笔记类博客,学习资料来源见参考!
【1】:MongoDB GridFS
【3】:MongoDB学习笔记(五) MongoDB文件存取操作
【4】:《MongoDB大数据权威处理指南》
【5】:java文件转二进制
【6】:Java将文件转为字节数组
【7】:java文件下载的几种方式
总结:绘上一张Kakfa架构思维大纲脑图(xmind)
[外链图片转存中…(img-E0sZPNEE-1713572893821)]
其实关于Kafka,能问的问题实在是太多了,扒了几天,最终筛选出44问:基础篇17问、进阶篇15问、高级篇12问,个个直戳痛点,不知道如果你不着急看答案,又能答出几个呢?
若是对Kafka的知识还回忆不起来,不妨先看我手绘的知识总结脑图(xmind不能上传,文章里用的是图片版)进行整体架构的梳理
梳理了知识,刷完了面试,如若你还想进一步的深入学习解读kafka以及源码,那么接下来的这份《手写“kafka”》将会是个不错的选择。
-
Kafka入门
-
为什么选择Kafka
-
Kafka的安装、管理和配置
-
Kafka的集群
-
第一个Kafka程序
-
Kafka的生产者
-
Kafka的消费者
-
深入理解Kafka
-
可靠的数据传递
-
Spring和Kafka的整合
-
SpringBoot和Kafka的整合
-
Kafka实战之削峰填谷
-
数据管道和流式处理(了解即可)
[外链图片转存中…(img-rzFFBfbr-1713572893822)]
[外链图片转存中…(img-r6oKtw9V-1713572893822)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-yly8OJBW-1713572893822)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!