1. 前言
这是复刻了慕课网教程《Spring Boot企业级博客系统实战视频教程》中的基于 MongoDB 及 Spring Boot 的文件服务器的实现,该教程的重点不是关于文件服务器的,但是我自己也想学个文件服务器,所以就复刻到它了。
让我纠结的事情是,SpringBoot虽然摒弃了大量的配置文件,使得开发变得十分轻松简单,但对我这种想要了解一些细节的新手并不十分友好,所以就自行用Spring+SpringMVC+MongoDB重写了一遍。
2. 实现
2.1 依赖
项目用maven构建,需要导入如下依赖:
<dependencies>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
<version>2.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>2.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>2.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.0.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring4</artifactId>
<version>3.0.9.RELEASE</version>
</dependency>
<dependency>
<groupId>nz.net.ultraq.thymeleaf</groupId>
<artifactId>thymeleaf-expression-processor</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>nz.net.ultraq.thymeleaf</groupId>
<artifactId>thymeleaf-layout-dialect</artifactId>
<version>2.2.0</version>
</dependency>
</dependencies>
这里${spring.version}
是5.0.6.RELEASE,看了下Spring-data-mongo的官方文档,似乎2.0.6以上只能用这个版本以上。
2.2 MongoDB与Spring的整合
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo.xsd">
<!-- 加载mongodb的属性配置文件 -->
<!--<context:property-placeholder location="classpath:config.properties"/>-->
<!-- 定义mongo对象,对应的是mongodb官方jar包中的Mongo,replica-set设置集群副本的ip地址和端口 -->
<mongo:mongo-client id="mongo" host="localhost" port="27017">
<!-- 一些连接属性的设置 -->
<mongo:client-options
connections-per-host="${mongo.connectionsPerHost}"
threads-allowed-to-block-for-connection-multiplier="${mongo.threadsAllowedToBlockForConnectionMultiplier}"
connect-timeout="${mongo.connectTimeout}"
max-wait-time="${mongo.maxWaitTime}"
socket-keep-alive="${mongo.socketKeepAlive}"
socket-timeout="${mongo.socketTimeout}"
/>
</mongo:mongo-client>
<!-- mongo的工厂,通过它来取得mongo实例,dbname为mongodb的数据库名,没有的话会自动创建 -->
<mongo:db-factory dbname="test" mongo-ref="mongo"/>
<!--spring提供的mongo操作的模板-->
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg ref="mongo"/>
<constructor-arg name="databaseName" value="${mongo.database}"/>
</bean>
<!-- 映射转换器,扫描back-package目录下的文件,根据注释,把它们作为mongodb的一个collection的映射 -->
<mongo:mapping-converter base-package="cn.aaa.bbbb.entity"/>
<!-- mongodb bean的仓库目录,会自动扫描扩展了MongoRepository接口的接口进行注入 -->
<mongo:repositories base-package="cn.aaa.bbbb.repository"/>
</beans>
关于MongoDB的配置我推荐去查阅官方文档,因为版本不同的话有点不太一样,但是目前来看这篇spring+mongodb的整合也应该够了。
然后是SpringMVC的配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<mvc:annotation-driven/>
<mvc:default-servlet-handler/>
<mvc:resources mapping="/css/**" location="/static/css/"/>
<mvc:resources mapping="/images/**" location="/static/images/"/>
<!--<mvc:resources mapping="/view/**" location="/static/view/"/>-->
<mvc:resources mapping="/js/**" location="/static/js/"/>
<mvc:resources mapping="/fonts/**" location="/static/font/"/>
<context:component-scan base-package="cn.tj212.xiaoyin.controller"/>
<!-- 配置模板解析器 -->
<bean id="templateResolver" class="org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver">
<property name="suffix" value=".html"/>
<property name="prefix" value="/WEB-INF/template/"/>
<property name="templateMode" value="HTML"/>
<property name="cacheable" value="false"/>
</bean>
<!-- 模板引擎 -->
<bean id="templateEngine" class="org.thymeleaf.spring4.SpringTemplateEngine">
<property name="templateResolver" ref="templateResolver"/>
</bean>
<!-- 配置视图解析器 -->
<bean id="viewResolver" class="org.thymeleaf.spring4.view.ThymeleafViewResolver">
<property name="templateEngine" ref="templateEngine"/>
<property name="characterEncoding" value="UTF-8"/>
</bean>
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10240000"/>
<property name="defaultEncoding" value="UTF-8"/>
<property name="maxUploadSizePerFile" value="10000000"/>
</bean>
</beans>
2.3 Java实现
Repository
import org.springframework.data.mongodb.repository.MongoRepository;
public interface FileRepository extends MongoRepository<FileEntity,String> {
}
Service
public interface FileService {
FileEntity saveFile(FileEntity file);
void removeFile(String id);
FileEntity getFileById(String id);
List<FileEntity> listFilesByPage(int pageIndex,int pageSize);
}
@Service
public class FileServiceImpl implements FileService {
@Autowired
private FileRepository fileRepository;
@Override
public FileEntity saveFile(FileEntity file) {
return fileRepository.save(file);
}
@Override
public void removeFile(String id) {
fileRepository.deleteById(id);
}
@Override
public FileEntity getFileById(String id) {
return fileRepository.findById(id).get();
}
@Override
public List<FileEntity> listFilesByPage(int pageIndex, int pageSize) {
Page<FileEntity> page=null;
List<FileEntity> list=null;
Sort sort=new Sort(Sort.Direction.DESC,"uploadDate");
Pageable pageable=new PageRequest(pageIndex,pageSize,sort);
page=fileRepository.findAll(pageable);
list=page.getContent();
return list;
}
}
Entity
@Document
public class FileEntity {
@Id
private String id;
private String name;
private String contentType;
private long size;
private Date uploadDate;
private String md5;
private byte[] content;
private String path;
//省略了setter、getter
...
public FileEntity(String name, String contentType, long size, byte[] content) {
this.name = name;
this.contentType = contentType;
this.uploadDate=new Date();
this.size = size;
this.content = content;
}
//覆盖equals方法
@Override
public boolean equals(Object obj) {
if (obj==this)
return true;
if (obj==null||obj.getClass()!=getClass()){
return false;
}
FileEntity fileInfo= (FileEntity) obj;
return Objects.equals(name,fileInfo.name)
&&Objects.equals(contentType,fileInfo.contentType)
&&Objects.equals(size,fileInfo.size)
&&Objects.equals(uploadDate,fileInfo.uploadDate)
&&Objects.equals(md5,fileInfo.md5)
&&Objects.equals(id,fileInfo.id);
}
//覆盖hashCode方法
@Override
public int hashCode() {
return Objects.hash(name,contentType,size,uploadDate,md5,id);
}
@Override
public String toString() {
return "FileEntity{" +
", name='" + name + '\'' +
", contentType='" + contentType + '\'' +
", size=" + size +
", uploadDate=" + uploadDate +
", md5='" + md5 + '\'' +
", content=" + Arrays.toString(content) +
", path='" + path + '\'' +
'}';
}
}
3 注意事项
好像是由于NullPointerException
的锅,2.0.6版本的MongoRepository
的返回类型变成了Optional
,我们需要调用该对象的get()
方法获取查询的目标对象,倒也不是特别麻烦。但是值得注意的是Optional
是JDK1.8以上版本新增的,所以如果需要在低版本的环境里运行的话,最好还是把版本降一降,至于具体什么版本的比较好,我看老卫的原课程里用的是Spring的4.3.8和spring-data-mongodb的1.10.3版本。