实现文件上传和下载功能
一、文件上传功能
目录结构
设立流程
- 设计数据表,将项目id和上传文件路径的对应关系存到数据库中。
结构包括:主键、项目id(外键)、文件目录、重命名后的文件名、原文件名。 - 逆向工程生成dao、po、mapper,xml
- 在project的edit.jsp中增加一段html的文件上传标记。
- 编写service和controller实现上传功能。
- 编辑页面显示文件,根据projectid找到对应的文件对象的,将原文件名显示在页面上。
1.数据库表结构
create table tb_files(
fid int primary key not null auto_increment,
projectid int,
path varchar(255),
filename varchar(255),
origname varchar(255)
)
2.dao包
通过逆向工程生成 TbFilesMapper接口
public interface TbFilesMapper {
int countByExample(TbFilesExample example);
int deleteByExample(TbFilesExample example);
int deleteByPrimaryKey(Integer fid);
int insert(TbFiles record);
int insertSelective(TbFiles record);
List<TbFiles> selectByExample(TbFilesExample example);
TbFiles selectByPrimaryKey(Integer fid);
int updateByExampleSelective(@Param("record") TbFiles record, @Param("example") TbFilesExample example);
int updateByExample(@Param("record") TbFiles record, @Param("example") TbFilesExample example);
int updateByPrimaryKeySelective(TbFiles record);
int updateByPrimaryKey(TbFiles record);
}
3.po包
TbFiles.java
public class TbFiles {
private Integer fid;
private Integer projectid;
private String path;
private String filename;
private String origname;
public Integer getFid() {
return fid;
}
public void setFid(Integer fid) {
this.fid = fid;
}
public Integer getProjectid() {
return projectid;
}
public void setProjectid(Integer projectid) {
this.projectid = projectid;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path == null ? null : path.trim();
}
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename == null ? null : filename.trim();
}
public String getOrigname() {
return origname;
}
public void setOrigname(String origname) {
this.origname = origname == null ? null : origname.trim();
}
}
4.service包
FileService接口
public interface FileService {
public List<TbFiles> query(int projectid);
}
FileServiceImpl.java
@Service//将该类注册到IOC容器中生成对应的Bean
public class FileServiceImpl implements FileService{
@Autowired
private TbFilesMapper filesMapper;
@Override
public List<TbFiles> query(int projectid) {
TbFilesExample example=new TbFilesExample();
TbFilesExample.Criteria criteria=example.createCriteria();
criteria.andProjectidEqualTo(projectid);
return filesMapper.selectByExample(example);
}
}
ProjectService接口
public interface ProjectService {
public void update(MultipartFile[] files,TbProject project,String realPath);
public TbProject queryById(int id);
}
ProjectServiceImpl.java
@Service
public class ProjectServiceImpl implements ProjectService{
@Autowired
private TbProjectMapper projectMapper;
@Autowired
private TbFilesMapper filesMapper;
@Override
public void update(MultipartFile[] files,TbProject project,String realPath) {
int count=0;
for(MultipartFile f:files){
//重命名
//截取后缀名
String hzm="";
int index=f.getOriginalFilename().lastIndexOf(".");
if(index!=-1){
hzm=f.getOriginalFilename().substring(index);
}
//生成一个不重复的名字
String name=String.valueOf(new Date().getTime())+(++count);//用当前时间的毫秒值作为名字,为了使名字不重复,count为计数器
//上传文件存储在部署路径的upload文件夹中,文件名是重命名的文件名
File dirFile=new File(realPath,"upload");//将部署的路径传进来
if(!dirFile.exists())//如果不存在就建立文件夹
dirFile.mkdir();
File saveFile=new File(dirFile,name+hzm);//dirFile为父文件夹,要存的文件名name+hzm
try {
f.transferTo(saveFile);
} catch (IOException e) {
e.printStackTrace();
}
//向数据库存储关系
TbFiles tbFiles=new TbFiles();
tbFiles.setProjectid(project.getProjectid());
tbFiles.setFilename(name+hzm);
tbFiles.setOrigname(f.getOriginalFilename());//源文件名
tbFiles.setPath(dirFile.getPath());//存储的路径
filesMapper.insert(tbFiles);
}
projectMapper.updateByPrimaryKeySelective(project);
}
}
5.controller包
ProjectController.java
@Controller
@RequestMapping("/project")
public class ProjectController {
@Autowired
private ProjectService projectService;//注入
@Autowired
private FileService fileService;
@RequestMapping("/edit")
public String edit(int id,Map map){
//查询项目经理的集合,查客户的集合,传到add.jsp页面
TbProject project=projectService.queryById(id);
List<TbFiles> files=fileService.query(id);
List<TbEmp> managers=empService.query(3);
List<TbCompany> companies=companyService.query();
map.put("managers",managers);
map.put("companies",companies);
map.put("project",project);
map.put("files",files);
return "/project/edit";
}
@RequestMapping("/update")
public String update(MultipartFile[] file, TbProject project, HttpServletRequest request){
projectService.update(file,project,request.getServletContext().getRealPath(""));//得到部署的路径传进去
return "redirect:/project/query";//重定向跳转
}
}
6.resources包
通过逆向工程生成的 TbFilesMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.hyxy.dao.TbFilesMapper" >
<resultMap id="BaseResultMap" type="com.hyxy.po.TbFiles" >
<id column="fid" property="fid" jdbcType="INTEGER" />
<result column="projectid" property="projectid" jdbcType="INTEGER" />
<result column="path" property="path" jdbcType="VARCHAR" />
<result column="filename" property="filename" jdbcType="VARCHAR" />
<result column="origname" property="origname" jdbcType="VARCHAR" />
</resultMap>
<update id="updateByPrimaryKeySelective" parameterType="com.hyxy.po.TbFiles" >
update tb_files
<set >
<if test="projectid != null" >
projectid = #{projectid,jdbcType=INTEGER},
</if>
<if test="path != null" >
path = #{path,jdbcType=VARCHAR},
</if>
<if test="filename != null" >
filename = #{filename,jdbcType=VARCHAR},
</if>
<if test="origname != null" >
origname = #{origname,jdbcType=VARCHAR},
</if>
</set>
where fid = #{fid,jdbcType=INTEGER}
</update>
<update id="updateByPrimaryKey" parameterType="com.hyxy.po.TbFiles" >
update tb_files
set projectid = #{projectid,jdbcType=INTEGER},
path = #{path,jdbcType=VARCHAR},
filename = #{filename,jdbcType=VARCHAR},
origname = #{origname,jdbcType=VARCHAR}
where fid = #{fid,jdbcType=INTEGER}
</update>
</mapper>
7.webapp
edit.jsp
<%--
Created by IntelliJ IDEA.
User: 86159
Date: 2022/7/5
Time: 8:54
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>项目管理系统</title>
<link rel="stylesheet" rev="stylesheet"
href="${pageContext.request.contextPath}/css/style.css" type="text/css" media="all" />
<style type="text/css">
<!--
.atten {font-size:12px;font-weight:normal;color:#F00;}
-->
</style>
<script src="${pageContext.request.contextPath}/js/jquery-1.9.1.min.js"></script>
<script>
$(function(){
$("#saveBtn").click(function(){
saveForm.submit();
});
$("#addFile").click(function(){
$("#filetd").append("<input type='file' name='file'/><br>")
});
});
</script>
</head>
<body class="ContentBody">
<form action="${pageContext.request.contextPath}/project/update" method="post" enctype="multipart/form-data"
name="saveForm" >
<input type="hidden" name="projectid" value="${project.projectid}">
<div class="MainDiv">
<table width="99%" border="0" cellpadding="0" cellspacing="0" class="CContent">
<tr>
<th class="tablestyle_title" >项目编辑</th>
</tr>
<tr>
<td class="CPanel">
<table border="0" cellpadding="0" cellspacing="0"
style="width:100%">
<TR>
<TD width="100%">
<fieldset style="height:100%;">
<legend>项目信息</legend>
<table border="0" cellpadding="2" cellspacing="1"
style="width:100%">
<tr>
<td nowrap align="right" width="15%">项目名称:</td>
<td width="35%"><input name='projectname'
value="${project.projectname}" type="text" class="text" style="width:154px" />
<span class="red">*</span></td>
<td nowrap align="right" width="18%">所属单位:</td>
<td width="35%">
<select name="companyid">
<option value="">请选择</option>
<c:forEach items="${companies}" var="c">
<option value="${c.companyid}"
<c:if test="${project.companyid==c.companyid}">selected</c:if> >${c.companyname}
</option>
</c:forEach>
</select>
<span class="red">*</span></td>
</tr>
<tr>
<td nowrap align="right" width="15%">项目金额:</td>
<td width="35%"><input name='amount'
value="${project.amount}" type="text" class="text" style="width:154px"/>
</td>
<td nowrap align="right" width="18%">开发人数:</td>
<td width="35%"><input name='prosum'
value="${project.prosum}" type="text" class="text" style="width:154px"/>
</td>
</tr>
<tr>
<td nowrap align="right" width="15%">项目经理:</td>
<td width="35%">
<select name="empid">
<option value="">请选择</option>
<c:forEach items="${managers}"
var="e">
<option value="${e.empid}" <c:if
test="${project.empid==e.empid}">selected</c:if> >${e.empname}</option>
</c:forEach>
</select>
</td>
<td nowrap align="right" width="18%">完成状态:</td>
<td width="35%">
<select name="state">
<option selected="selected">请选择</option>
<option value="0" <c:if test="${project.state==0}">selected</c:if> >需求</option>
<option value="1" <c:if test="${project.state==1}">selected</c:if> >开发</option>
<option value="2" <c:if test="${project.state==2}">selected</c:if> >测试</option>
<option value="3" <c:if test="${project.state==3}">selected</c:if> >完成</option>
</select>
</td>
</tr>
<tr>
<td nowrap align="right" width="15%">预算总成本:</td>
<td width="35%"><input name='budget'
value="${project.budget}" type="text" class="text" style="width:154px" />
</td>
<td nowrap="nowrap" align="right">开始日期:</td>
<td><input name='realbegindate'
value="<fmt:formatDate value='${project.realbegindate}' pattern="yyyy-MM-dd"/>" type="text" class="text" style="width:154px"/> </td>
</tr>
<tr>
<td nowrap="nowrap" align="right">完成日期:</td>
<td><input name='realenddate'
value="<fmt:formatDate value='${project.realenddate}' pattern="yyyy-MM-dd"/>" type="text" class="text" style="width:154px" />
</td>
<td align="right" >优先级:</td>
<td ><select name="priority" >
<option selected="selected">请选择</option>
<option value="0" <c:if test="${project.priority==0}">selected</c:if> >普通</option>
<option value="1" <c:if test="${project.priority==1}">selected</c:if> >急</option>
<option value="2" <c:if test="${project.priority==2}">selected</c:if> >特急</option>
</select></td>
</tr>
<tr>
<td width="15%" nowrap align="right">备注:
</td>
<td colspan="3"><textarea name="descript"
cols="100" rows="10">${project.descript}</textarea></td>
</tr>
<tr>
<td colspan="4" nowrap align="left"><a id="addFile" href="javascript:void(0);">添加文件</a></td>
</tr>
<tr>
<td colspan="4" nowrap align="left">
<c:forEach items="${files}" var="f">
${f.origname} <a href="${pageContext.request.contextPath}/project/download?id=${f.fid}">下载</a> <a href="javascript:void(0);">删除</a><br>
</c:forEach>
</td>
</tr>
<tr>
<td colspan="4" id="filetd" nowrap align="left"></td>
</tr>
</table>
<br/>
</fieldset> </TD>
</TR>
</TABLE>
</td>
</tr>
<TR>
<TD colspan="2" align="center" height="50px">
<input type="button" name="Submit" value="保存" id="saveBtn"
class="button" />
<input type="button" name="Submit2" value="返回" class="button"
onclick="window.history.go(-1);"/></TD>
</TR>
</TABLE>
</td>
</tr>
</table>
</div>
</form>
</body>
</html>
8.spring的xml配置文件
applicationContext.xml
<?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:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
xmlns:tx="http://www.springframework.org/schema/tx" 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://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/project?useUnicode=true&characterEncoding=utf8" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="mapperLocations" value="classpath*:com/hyxy/mapper/*.xml"></property>
<property name="plugins">
<array>
<bean class="com.github.pagehelper.PageInterceptor">
<property name="properties">
<value>
helperDialect=mysql
reasonable=true
</value>
</property>
</bean>
</array>
</property>
</bean>
<mybatis-spring:scan base-package="com.hyxy.dao"/>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<tx:annotation-driven transaction-manager="txManager" />
<context:component-scan base-package="com.hyxy.service"></context:component-scan>
</beans>
9.导入的依赖
<!-- 文件上传包 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
10.显示效果
浏览器访问 项目查询页面–点击编辑按钮–点击添加文件超链接–选择上传文件–点击保存按钮
http://localhost/8080/project/project/query
添加文件
再次访问编辑页面可查看上传的文件
数据库存储的projectid和上传文件的关系表
二、文件下载功能
目录结构
1.service包
FileService接口
public interface FileService {
public TbFiles queryById(int fid);
}
FileServiceImpl.java
@Service
public class FileServiceImpl implements FileService{
@Autowired
private TbFilesMapper filesMapper;
@Override
public TbFiles queryById(int fid) {
return filesMapper.selectByPrimaryKey(fid);
}
}
2.controller包
ProjectController.java
@Controller
@RequestMapping("/project")
public class ProjectController {
@Autowired
private ProjectService projectService;//注入
@Autowired
private EmpService empService;
@Autowired
private CompanyService companyService;
@Autowired
private FileService fileService;
@RequestMapping("/update")
public String update(MultipartFile[] file, TbProject project, HttpServletRequest request){
projectService.update(file,project,request.getServletContext().getRealPath(""));
return "redirect:/project/query";
}
@RequestMapping("/download")
public ResponseEntity<byte[]> download(int id){
TbFiles files=fileService.queryById(id);
File downloadFile=new File(files.getPath(),files.getFilename());//要下载的文件
HttpHeaders headers = new HttpHeaders();
//通知浏览器以attachment(下载方式)打开图片
headers.setContentDispositionFormData("attachment", files.getOrigname());//原文件名
//application/octet-stream : 二进制流数据(最常见的文件下载)。
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
try {
return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(downloadFile),
headers, HttpStatus.CREATED);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
3.功能测试
点击下载功能的超链接即可下载到本地