搞java的这些年

刚好看到一个哥们的回贴,关于工作这些年做的事情和经验。一时心血来潮,发起一贴。借此看看大家的经历,也许有可借鉴的地方。欢迎拍砖。
2004年6月毕业于某大学某计算机专业。技术基础:学的是C,毕业前半年现学了Java,只懂jsp,html,css.

2005年:进行一些联通公司的项目开发,闷头进行模块开发。技术jsp,servlet,javabean,portal,数据同步.后期项目开始使用struts1和spring.没有亮点。

2006年:还是进行一些联通、移动方面的项目开发,还是闷头进行模块开发。技术开始慢慢转向struts+hibernate.还是没有亮点。

2007年:进行某oss产品开发,周期也比较长,一整年。这回算是有了些亮点,进入核心开发行列。进行了计费账务,银行接口等N多方面的开发,全面深入quartz,socket(quickserver框架)开发。开始接触webservice.正式进入freemarker+webwork2+spring+hibernate时代。开始学习应用设计模式、TDD这些东东,不过还是一知半解。进入javaeye大本营。自我总结:这一年对技术的提升最明显。

2008年:进行中国移动的一个项目开发。开始进入需求、设计、架构行列,基本上这方面部分经理授权给我干。由于没有经验,需求、设计、架构都做得比较烂,现在想来都好笑。不过基本上顺利完成了项目,老板拿到钱就行,可不是。技术方面开始转入struts2(和webwork2没有区别,无缝转入)。spring,hibernate还在用。开始搞起Mina,XML,jquery,ajax等东东。自我总结:在做需求方面,这年进步比较明显,和总经理学到了很多蛋B的技术。

2009年:首先是参加老家联通的一个项目。角色-项目经理,出差。手下成员,几个毕业学生。这个项目感觉比较失败,由于没有管理经验,做得很不好。当时几个毕业的学生,其实人都不错,最后由于我的决定,没录取其中一个。其实我也不知道老板是不是想全招,让我做决定,我就排除了一个。希望那个小弟不要怪我,你其实人不错。这几年我一直内疚。架构技术方面是seam,jpa,不过我现在还是没搞明白seam这东东.因为当时我主要负责管理,还有后台oracle大数据量的同步还有数据分析,存偖过程、dts、集群。后半年还是联通的项目,角色-高程,专注于web service接口的开发。自我总结:失败的项目管理,给了我很大的启示。

2010:角色-Team Leader.前几个月参加了某电子商务的开发。重操freemarker进行模板定制开发,深入jquery,开始了flex,springmvc,memcahced,缓存和分布式、负载均衡等web之旅。下半年又搞上联通项目。参与需求调研、设计和小组管理。未进行一点开发的小半年,几个小弟都很争气,没用我操心。开始深入设计模式和系统架构等很蛋疼的东西。开始搞起敏捷和scrum,并试着在项目中使用。自我总结:进行自我反省和思想沉淀的一年。

2011:在路上。。。
09-09
<think> 根据用户的需求,我们需要完成以下任务: 1. 接收通过HTTP接口上传的ZIP文件 2. 从ZIP文件中提取所有JPG文件(不区分大小写,即包括.jpg, .JPG等) 3. 将提取的JPG文件保存到指定目录,并生成相对路径(相对于某个基础目录) 4. 将这些相对路径写入数据库 我们将使用Java技术栈,假设使用Spring Boot框架来实现。 步骤: 1. 创建一个Spring Boot项目,包含spring-boot-starter-web(用于处理HTTP请求)和spring-boot-starter-data-jpa(用于操作数据库)等依赖。 2. 配置数据库(例如H2、MySQL等)。 3. 实现文件上传接口,接收MultipartFile类型的ZIP文件。 4. 使用java.util.zip包处理ZIP文件,遍历每个条目,筛选出JPG文件。 5. 将JPG文件保存到服务器上的指定目录(例如:./extracted-images/)。 6. 生成相对路径(例如:extracted-images/photo1.jpg)。 7. 将相对路径保存到数据库中。 注意:由于ZIP文件中可能包含目录结构,我们需要在保存文件时保持相对路径。但为了安全,我们应避免使用绝对路径,并且要注意防止路径遍历漏洞(例如zip中可能包含"../"这样的路径)。我们将对文件名进行安全处理。 以下详细步骤: 1. 创建实体类(ImageEntity)用于映射数据库表。 2. 创建Repository接口(ImageRepository)用于数据库操作。 3. 实现Controller,处理上传请求。 代码示例: 1. 实体类: ```java import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @Entity public class ImageEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String relativePath; // getters and setters } ``` 2. Repository接口: ```java import org.springframework.data.jpa.repository.JpaRepository; public interface ImageRepository extends JpaRepository<ImageEntity, Long> { } ``` 3. Controller类: ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import java.io.*; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @RestController public class UploadController { @Autowired private ImageRepository imageRepository; // 定义存储提取图片的基础目录(相对路径) private static final String BASE_DIR = "extracted-images/"; @PostMapping("/upload") public ResponseEntity<String> uploadZip(@RequestParam("file") MultipartFile file) { if (file.isEmpty()) { return ResponseEntity.badRequest().body("Please upload a ZIP file."); } try (InputStream inputStream = file.getInputStream(); ZipInputStream zipInputStream = new ZipInputStream(inputStream)) { // 确保基础目录存在 File baseDirFile = new File(BASE_DIR); if (!baseDirFile.exists()) { baseDirFile.mkdirs(); } ZipEntry entry; while ((entry = zipInputStream.getNextEntry()) != null) { // 只处理文件(跳过目录) if (!entry.isDirectory()) { String entryName = entry.getName(); // 仅处理JPG文件(不区分大小写) if (entryName.toLowerCase().endsWith(".jpg")) { // 安全处理:防止路径遍历攻击(去掉路径中的..等) String safeEntryName = new File(entryName).getName(); // 这里只取文件名,丢弃目录结构? // 但是用户需求是生成相对路径,可能需要保留目录结构(但要安全) // 我们使用一个更安全的方法:将路径中的非法字符去掉,并限制在基础目录下 // 这里我们使用Apache Commons IO中的FilenameUtils来规范化路径,但为了减少依赖,我们手动处理 // 注意:这里我们决定保留ZIP中的相对目录结构,但限制在BASE_DIR下 File outputFile = new File(BASE_DIR, entryName); // 为了防止跳出基础目录,检查规范化的路径是否以基础目录开头 String canonicalBasePath = baseDirFile.getCanonicalPath(); String canonicalOutputPath = outputFile.getCanonicalPath(); if (!canonicalOutputPath.startsWith(canonicalBasePath)) { // 检测到路径遍历攻击 continue; } // 创建父目录(如果不存在) File parent = outputFile.getParentFile(); if (!parent.exists()) { parent.mkdirs(); } // 写入文件 try (FileOutputStream outputStream = new FileOutputStream(outputFile)) { byte[] buffer = new byte[1024]; int length; while ((length = zipInputStream.read(buffer)) > 0) { outputStream.write(buffer, 0, length); } } // 生成相对路径(相对于当前工作目录?或者我们只存储从BASE_DIR开始的相对路径?) // 这里我们存储相对于应用运行目录的路径:BASE_DIR + entryName String relativePath = BASE_DIR + entryName; // 保存到数据库 ImageEntity image = new ImageEntity(); image.setRelativePath(relativePath); imageRepository.save(image); } } zipInputStream.closeEntry(); } return ResponseEntity.ok("ZIP file processed successfully."); } catch (IOException e) { e.printStackTrace(); return ResponseEntity.internalServerError().body("Error processing ZIP file."); } } } ``` 注意:上面的代码中,我们处理了路径遍历攻击,通过检查规范化的输出文件路径是否在基础目录内。但是,由于我们使用了`new File(BASE_DIR, entryName)`,如果`entryName`包含`..`,那么`getCanonicalPath`会解析出真实路径,然后我们检查这个路径是否以基础目录的规范路径开始。 但是,我们还需要注意,如果ZIP中的文件非常多,可能会占用大量内存,我们使用缓冲区逐块读写。另外,我们只提取并保存了JPG文件。 4. 配置数据库:在application.properties中配置(以H2内存数据库为例) ``` spring.datasource.url=jdbc:h2:mem:testdb spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password=password spring.jpa.database-platform=org.hibernate.dialect.H2Dialect ``` 5. 运行应用,使用Postman或curl发送POST请求到/upload,表单字段为file,内容为ZIP文件。 以上代码提供了基本功能,但还有一些改进空间: - 并发处理:如果同时有多个上传,要考虑线程安全和资源竞争。 - 异常处理:更细致的异常捕获和日志记录。 - 性能:大文件上传可能需要流式处理,避免内存溢出。 - 事务管理:如果保存文件或数据库操作失败,可能需要回滚(例如删除已保存的文件)。 另外,我们只存储了相对路径,实际应用中可能需要存储更多信息(如原始ZIP文件名、上传时间等)。 生成相关问题: 1. 如何防止ZIP文件中的路径遍历漏洞? 2. 当上传的ZIP文件非常大时,如何优化内存使用? 3. 如何支持多种图片格式(例如jpeg, png等)? 4. 如何处理重复的图片路径? 5. 如何将提取的图片存储在云存储(如MinIO)而非本地? 注意:上述引用仅作为背景参考,实际回答中并未直接引用,因此无需添加引用标识。 </think> ### Java实现从接口上传的ZIP文件中提取JPG文件并写入数据库 #### 1. 创建Spring Boot项目依赖 在`pom.xml`中添加必要依赖: ```xml <dependencies> <!-- Spring Web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 数据库 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <!-- 文件处理 --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.11.0</version> </dependency> </dependencies> ``` #### 2. 数据库实体类 ```java @Entity public class ImageFile { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String relativePath; // 相对路径 // getters/setters } ``` #### 3. Repository接口 ```java public interface ImageRepository extends JpaRepository<ImageFile, Long> { } ``` #### 4. 文件上传控制器 ```java @RestController public class FileUploadController { @Value("${file.upload-dir}") private String uploadDir; // 配置在application.properties @Autowired private ImageRepository imageRepository; @PostMapping("/upload") public ResponseEntity<String> handleFileUpload(@RequestParam("file") MultipartFile file) { try { // 创建临时ZIP文件 File zipFile = new File(uploadDir + "temp.zip"); file.transferTo(zipFile); // 处理ZIP文件 processZipFile(zipFile); return ResponseEntity.ok("文件处理成功"); } catch (Exception e) { return ResponseEntity.status(500).body("处理失败: " + e.getMessage()); } } private void processZipFile(File zipFile) throws IOException { try (ZipInputStream zipIn = new ZipInputStream(new FileInputStream(zipFile))) { ZipEntry entry; while ((entry = zipIn.getNextEntry()) != null) { if (!entry.isDirectory() && entry.getName().toLowerCase().endsWith(".jpg")) { // 生成相对路径(示例:extracted/2023/images/photo1.jpg) String relativePath = "extracted/" + LocalDate.now().getYear() + "/" + entry.getName(); // 保存文件到本地 saveJpgFile(zipIn, relativePath); // 写入数据库 ImageFile image = new ImageFile(); image.setRelativePath(relativePath); imageRepository.save(image); } zipIn.closeEntry(); } } } private void saveJpgFile(ZipInputStream zipIn, String relativePath) throws IOException { File outputFile = new File(uploadDir + relativePath); outputFile.getParentFile().mkdirs(); // 创建父目录 FileUtils.copyInputStreamToFile(zipIn, outputFile); } } ``` #### 5. 配置文件(`application.properties`) ```properties # 文件存储目录 file.upload-dir=./uploads/ # 数据库配置 spring.datasource.url=jdbc:h2:mem:testdb spring.datasource.driverClassName=org.h2.Driver spring.jpa.database-platform=org.hibernate.dialect.H2Dialect ``` #### 6. 安全注意事项 1. **路径遍历防护**:在保存文件前验证路径 ```java if (entry.getName().contains("..")) { throw new SecurityException("非法路径: " + entry.getName()); } ``` 2. **文件类型验证**: ```java String contentType = Files.probeContentType(Paths.get(entry.getName())); if (!"image/jpeg".equals(contentType)) { continue; } ``` #### 工作流程说明 1. 客户端通过`POST /upload`接口上传ZIP文件 2. 服务器将ZIP保存为临时文件 3. 使用`ZipInputStream`遍历ZIP条目 4. 对每个JPG文件: - 生成相对路径(如`extracted/2023/images/photo1.jpg`) - 保存到配置的存储目录 - 将路径写入数据库 5. 返回处理结果 #### 性能优化建议 1. 使用流式处理避免内存溢出 2. 对大文件使用分块读取: ```java byte[] buffer = new byte[8192]; int len; while ((len = zipIn.read(buffer)) > 0) { output.write(buffer, 0, len); } ``` 3. 数据库批量插入: ```java List<ImageFile> batch = new ArrayList<>(); // ...处理文件时添加到batch imageRepository.saveAll(batch); // 每100条批量提交 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值