以下是以插入广告(附带图片)为例进行讲解:
(一)广告类
1.Advertisement类
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Advertisement extends Entity {
private String title;
private String imgFileName;
private String link;
private Integer weight;
}
备注:
问题:为什么这里不设计成图片地址(imgUrl),却设计成了图片名称(imgFileName)?
原因:
对于并发访问量大的应用,专门有服务器集群来存放各种静态资源(比如图片)是很正常的事。有时候很容易一台服务器崩 溃了,其他服务器要顶上,这个时候快速更换“访问路径”是很常见的事。“访问路径”其实变的只是存放文件的“文件夹”,不变的就是文件的名称。所以通常的做法是保存文件的文件名,将“文件夹”的地址写在配置文件中,当我们接收前端传过来的文件时,读取配置文件中的“文件夹地址”,和数据库中文件的“文件名”进行拼接,即可得到上传文件的保存路径。这样做高效、简单!
关于图片的访问路径,同理!将“访问路径”的前缀写在配置文件中!
2.AdvertisementDto类
public class AdvertisementDto extends Advertisement {
private String img;
/**
* 要和前端上传控件的name保持一致,以实现前后端数据绑定
*/
private MultipartFile imgFile;
}
问题:已经有“Advertisement”类了,为什么还要有个AdvertisementDto类?
原因:
上面的“Advertisement”类只要是和数据库一一对应,但是我们从前端获取的数据并不一定和“Advertisement”类一一对应,比如:前端会上传一个文件,上传文件一般都是“MultipartFile”对象,“Advertisement”类中就没有。为了解决数据传输和数据保存的不一致性,一般我们会选择加一个“*Dto”类(Dto:Data Transfer Object简称),这个类一般会继承和数据库对应的类(Advertisement),并加上没有的元素(String img和MultipartFile imgFile)
(二)上传文件的流程
1.控制层(Controller类)
@RequestMapping(value = "/add", method = RequestMethod.POST)
public String add(AdvertisementDto advertisementDto){
advertisementService.addAdvertisement(advertisementDto);
return "/content/adAdd";
}
2.服务层(Service类)
(1)接口
public interface AdvertisementService {
/**
* 插入广告
* @param advertisementDto 新增广告
* @return true新增成功;false失败
*/
boolean addAdvertisement(AdvertisementDto advertisementDto);
}
(2)实现类
@Service
public class AdvertisementServiceImpl implements AdvertisementService {
@Autowired
private AdvertisementDao advertisementDao;
/**
* “@Value”注解用于读取Spring项目中的属性文件的值,value为这样的形式:"${key}"
*/
@Value("${advertisement.imgSavePath}")
private String imgSavePath;
@Override
public boolean addAdvertisement(AdvertisementDto advertisementDto) {
Advertisement advertisement = new Advertisement();
advertisement.setTitle(advertisementDto.getTitle());
advertisement.setImgFileName(advertisementDto.getImgFileName());
advertisement.setLink(advertisementDto.getLink());
advertisement.setWeight(advertisementDto.getWeight());
/*----------------将前端上传的文件保存到服务器---------------------*/
//从Controller中获取的前端上传的文件
MultipartFile imgMultipartFile = advertisementDto.getImgFile();
if (imgMultipartFile != null && imgMultipartFile.getSize() > 0){
try {
//判断“保存路径”是否存在,不存在,则创建
File fileFolder = new File(imgSavePath);
if (!fileFolder.exists()){
fileFolder.mkdirs();
}
/*
* 获取文件在服务器上的地址:
* imgSavePath:配置文件中读取的“保存路径”
* System.currentTimeMillis() + "_":防止同名的文件无法上传,所以在路径上加了个时间戳
* imgMultipartFile.getOriginalFilename():上传文件的名字
*/
String fileName = System.currentTimeMillis() + "_" + imgMultipartFile.getOriginalFilename();
String dst = imgSavePath + fileName;
File file = new File(dst);
/*
* transferTo(file):Spring容器提供的一个“MultipartFile”对象(该对象实现接收上传文件)的方法,实现将接
* 收到的上传文件转移到指定位置
*/
imgMultipartFile.transferTo(file);
advertisement.setImgFileName(fileName);
advertisementDao.insertAdvertisement(advertisement);
return true;
} catch (IOException e) {
return false;
}
}
/*----------------将前端上传的文件保存到服务器---------------------*/
return false;
}
}
3.dao层
public interface AdvertisementDao {
int insertAdvertisement(Advertisement advertisement);
}
4.Mybatis配置文件
。。。。
(三)完善上传文件需要用到的配置文件
1.增加POM依赖
<!-- Spring配置上传文件解析器需要用到的依赖 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
备注:像这种中途加依赖的,当遇到“ClassNotFoundException”时,大多是因为jar包没有被放到项目中去,具体参见“https://mp.csdn.net/postedit/80218191”
2.在Spring配置文件(applicationContext-web.xml)中配置文件上传解析器
<!-- Spring配置上传文件解析器需要用到的依赖 -->
<!-- 配置文件上传解析器 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="20000000"/>
<property name="defaultEncoding" value="utf-8"/>
</bean>