SpringBoot上傳下載文件及在線預覽
今天大概就說說如何使用SpringBoot進行上傳和下載以及在線預覽文件
本篇主要介紹上傳下載的功能,對於界面就簡單一點,大致如下:
一、老規矩還是先看看小項目的目錄結構:
二、添加對應的pom依賴
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
三、創建相應的配置
spring.application.name=files
server.port=8080
server.servlet.context-path=/files
spring.thymeleaf.cache=false
spring.thymeleaf.suffix=.html
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.prefix=classpath:/templates/
spring.resources.static-locations=classpath:/templates/,classpath:/static/,file:${upload.dir}
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/files?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=root
mybatis.mapper-locations=classpath:/com/baizhi/mapper/*.xml
mybatis.type-aliases-package=com.baizhi.entity
#控制台進行打印日志
logging.level.root=info
logging.level.com.baizhi.dao=debug
#上傳和下載文件的路徑
upload.dir=D:/idea_project/java/files/target/classes/static
四、先准備登陸界面的工作
1、創建實體類
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Accessors(chain=true)
public class User {
private Integer id;
private String username;
private String password;
}
2、創建對應的dao層
public interface UserDAO {
User login(User user);
}
3、創建對應的mapper映射文件
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.baizhi.dao.UserDAO">
<!--login-->
<select id="login" parameterType="User" resultType="com.baizhi.entity.User">
select id,username,password
from t_user
where username=#{username}
and password = #{password}
</select>
</mapper>
4、創建業務層接口及實現類
public interface UserService {
User login(User user);
}
@Service
@Transactional
public class UserServciceImpl implements UserService{
@Autowired
private UserDAO userDAO;
@Override
@Transactional(propagation = Propagation.SUPPORTS)
public User login(User user) {
return userDAO.login(user);
}
}
5、創建控制器
@Controller
@RequestMapping("user")
@Slf4j
public class UserController {
@Autowired
private UserService userService;
/**
* 登錄方法
*/
@PostMapping("login")
public String login(User user, HttpSession session){
User userDB = userService.login(user);
if(userDB!=null){
session.setAttribute("user",userDB);
return "redirect:/file/showAll";
}else{
return "redirect:/index";
}
}
}
6、創建登陸界面
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>用戶登錄</title>
</head>
<body>
<h1>歡迎訪問用戶文件管理系統</h1>
<form th:action="@{/user/login}" method="post">
username: <input type="text" name="username"/> <br>
password: <input type="text" name="password"/> <br>
<input type="submit" value="登錄">
</form>
</body>
</html>
7、查看運行后對應的界面
五、進行主界面的操作
1、創建實體類
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Accessors(chain=true)
public class UserFile {
private Integer id;
private String oldFileName;
private String newFileName;
private String ext;
private String path;
private String size;
private String type;
private String isImg;
private Integer downcounts;
private Date uploadTime;
private Integer userId; //用戶外鍵
}
2、創建對應的dao層
public interface UserFileDAO {
//根據登錄用戶id獲取用戶的文件列表
List<UserFile> findByUserId(Integer id);
//保存用戶的文件記錄
void save(UserFile userFile);
//根據文件id獲取文件信息
UserFile findById(String id);
//根據id更新下載次數
void update(UserFile userFile);
//根據id刪除記錄
void delete(String id);
}
3、創建dao層對應的mapper映射文件
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.baizhi.dao.UserFileDAO">
<!--根據用戶id查詢當前用戶的文件信息-->
<select id="findByUserId" parameterType="Integer" resultType="com.baizhi.entity.UserFile">
select id,oldFileName,newFileName,ext,path,size,type,isImg,downcounts,uploadTime,userId
from t_files
where userId=#{id}
</select>
<!--保存文件信息-->
<insert id="save" parameterType="com.baizhi.entity.UserFile" useGeneratedKeys="true" keyProperty="id">
insert into t_files
values (#{id},#{oldFileName},#{newFileName},
#{ext}, #{path},#{size},#{type},
#{isImg},#{downcounts}, #{uploadTime},#{userId})
</insert>
<!--根據id獲取文件信息-->
<select id="findById" parameterType="String" resultType="com.baizhi.entity.UserFile">
select id,oldFileName,newFileName,ext,path,size,type,isImg,downcounts,uploadTime,userId
from t_files
where id = #{id}
</select>
<!--更新下載次數-->
<update id="update" parameterType="com.baizhi.entity.UserFile" >
update t_files set downcounts=#{downcounts} where id=#{id}
</update>
<!--根據id刪除記錄-->
<delete id="delete" parameterType="String">
delete from t_files where id=#{id}
</delete>
</mapper>
4、創建對應的業務層接口及實現類
public interface UserFileService {
List<UserFile> findByUserId(Integer id);
void save(UserFile userFile);
UserFile findById(String id);
void update(UserFile userFile);
void delete(String id);
}
@Service
@Transactional
public class UserFileServiceImpl implements UserFileService {
@Autowired
private UserFileDAO userFileDAO;
@Override
public List<UserFile> findByUserId(Integer id) {
return userFileDAO.findByUserId(id);
}
@Override
public void delete(String id) {
userFileDAO.delete(id);
}
@Override
public void update(UserFile userFile) {
userFileDAO.update(userFile);
}
@Override
public UserFile findById(String id) {
return userFileDAO.findById(id);
}
@Override
public void save(UserFile userFile) {
//userFile.setIsImg()? //是否是圖片 解決方案: 當類型中含有image時說明當前類型一定為圖片類型
String isImg = userFile.getType().startsWith("image")?"是":"否";
userFile.setIsImg(isImg);
userFile.setDowncounts(0);
userFile.setUploadTime(new Date());
userFileDAO.save(userFile);
}
}
5、創建控制器(重點)
- 上傳文件(且保存到i數據庫中)
@PostMapping("upload")
public String upload(MultipartFile aaa, HttpSession session) throws IOException {
//獲取上傳文件用戶id
User user = (User) session.getAttribute("user");
//獲取文件原始名稱
String oldFileName = aaa.getOriginalFilename();
//獲取文件后綴
String extension = "." + FilenameUtils.getExtension(aaa.getOriginalFilename());
//生成新的文件名稱
String newFileName = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + UUID.randomUUID().toString().replace("-", "") + extension;
//文件大小
Long size = aaa.getSize();
//文件類型
String type = aaa.getContentType();
//處理根據日期生成目錄
//String realPath = ResourceUtils.getURL("classpath:").getPath() + "/static/files";
String dateFormat = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
String dateDirPath = uploadPath + "/files/" + dateFormat;
File dateDir = new File(dateDirPath);
if (!dateDir.exists()) dateDir.mkdirs();
//處理文件上傳
aaa.transferTo(new File(dateDir, newFileName));
//將文件信息放入數據庫保存
UserFile userFile = new UserFile();
userFile.setOldFileName(oldFileName).setNewFileName(newFileName).setExt(extension).setSize(String.valueOf(size))
.setType(type).setPath("/files/" + dateFormat).setUserId(user.getId());
userFileService.save(userFile);
return "redirect:/file/showAll";
}
- 下載文件(在線預覽)
@GetMapping("download")
public void download(String openStyle, String id, HttpServletResponse response) throws IOException {
//獲取打開方式
openStyle = openStyle == null ? "attachment" : openStyle;
//獲取文件信息
UserFile userFile = userFileService.findById(id);
//點擊下載鏈接更新下載次數
if ("attachment".equals(openStyle)) {
userFile.setDowncounts(userFile.getDowncounts() + 1);
userFileService.update(userFile);
}
//根據文件信息中文件名字 和 文件存儲路徑獲取文件輸入流
String realpath = ResourceUtils.getURL("classpath:").getPath() + "/static" + userFile.getPath();
//獲取文件輸入流
FileInputStream is = new FileInputStream(new File(realpath, userFile.getNewFileName()));
//附件下載
response.setHeader("content-disposition", openStyle + ";fileName=" + URLEncoder.encode(userFile.getOldFileName(), "UTF-8"));
//獲取響應輸出流
ServletOutputStream os = response.getOutputStream();
//文件拷貝
IOUtils.copy(is, os);
IOUtils.closeQuietly(is);
IOUtils.closeQuietly(os);
}
- 展示所有文件信息
@GetMapping("showAll")
public String findAll(HttpSession session, Model model) {
//在登錄的session中獲取用戶的id
User user = (User) session.getAttribute("user");
//根據用戶id查詢有的文件信息
List<UserFile> userFiles = userFileService.findByUserId(user.getId());
//存入作用域中
model.addAttribute("files", userFiles);
return "showAll";
}
- 刪除文件(及數據庫中的)
@GetMapping("delete")
public String delete(String id) throws FileNotFoundException {
//根據id查詢信息
UserFile userFile = userFileService.findById(id);
//刪除文件
String realPath = ResourceUtils.getURL("classpath:").getPath() + "/static" + userFile.getPath();
File file = new File(realPath, userFile.getNewFileName());
if(file.exists())file.delete();//立即刪除
//刪除數據庫中記錄
userFileService.delete(id);
return "redirect:/file/showAll";
}
- 返回當前的文件列表(json格式數據)
@GetMapping("findAllJSON")
@ResponseBody
public List<UserFile> findAllJSON(HttpSession session, Model model) {
//在登錄的session中獲取用戶的id
User user = (User) session.getAttribute("user");
//根據用戶id查詢有的文件信息
List<UserFile> userFiles = userFileService.findByUserId(user.getId());
return userFiles;
}
6、創建對應的界面
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>用戶文件列表頁面</title>
<script th:src="@{/js/jquery-3.4.1.min.js}"></script>
<script>
$(function(){
var time;
$("#start").click(function(){
console.log("開啟定時更新.........");
time = setInterval(function () {
$.get("[[@{/file/findAllJSON}]]", function (res) {
//遍歷
$.each(res, function (index, file) {
$("#" + file.id).text(file.downcounts);
})
});
}, 3000);
});
$("#stop").click(function () {
console.log("關閉定時更新");
clearInterval(time);
});
});
</script>
</head>
<body>
<h1>歡迎: <span th:if="${session.user!=null}" th:text="${session.user.username}"/></h1>
<h3>文件列表:</h3>
<button id="start">開啟定時更新</button>
<button id="stop">結束定時更新</button>
<table border="1px">
<tr>
<th>ID</th>
<th>文件原始名稱</th>
<th>文件的新名稱</th>
<th>文件后綴</th>
<th>存儲路徑</th>
<th>文件大小</th>
<th>類型</th>
<th>是否是圖片</th>
<th>下載次數</th>
<th>上傳時間</th>
<th>操作</th>
</tr>
<tr th:each="file,fileStat:${files}">
<td><span th:text="${file.id}"/></td>
<td><span th:text="${file.oldFileName}"/></td>
<td><span th:text="${file.newFileName}"/></td>
<td><span th:text="${file.ext}"/></td>
<td><span th:text="${file.path}"/></td>
<td><span th:text="${file.size}"/></td>
<td><span th:text="${file.type}"/></td>
<td>
<img th:if="${file.isImg}=='是'" style="width: 100px;height: 40px;" th:src="${#servletContext.contextPath}+${file.path}+'/'+${file.newFileName}" alt="">
<span th:if="${file.isImg}!='是'" th:text="${file.isImg}"/>
</td>
<td th:id="${file.id}"><span th:text="${file.downcounts}"/></td>
<td><span th:text="${#dates.format(file.uploadTime,'yyyy-MM-dd HH:mm:ss')}"/></td>
<td>
<a th:href="@{/file/download(id=${file.id})}">下載</a>
<a th:href="@{/file/download(id=${file.id},openStyle='inline')}">在線打開</a>
<a th:href="@{/file/delete(id=${file.id})}">刪除</a>
</td>
</tr>
</table>
<hr>
<h3>上傳文件:</h3>
<form th:action="@{/file/upload}" method="post" enctype="multipart/form-data">
<input type="file" name="aaa"> <input type="submit" value="上傳文件">
</form>
</body>
</html>
六、創建攔截器
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
Object user = session.getAttribute("user");
if(user!=null) return true;
response.sendRedirect(request.getContextPath()+"/index");
return false;
}
}
七、創建過濾器
@Configuration
public class InterceptorConfig extends WebMvcConfigurationSupport {
@Value("${upload.dir}")
private String upload;
@Override
protected void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/file/**")
.excludePathPatterns("/css/**")
.excludePathPatterns("/js/**");//放行靜態資源 靜態資源被認為是一個控制器請求
}
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**") //代表以什么樣的請求路徑訪問靜態資源
.addResourceLocations("classpath:/static/")
.addResourceLocations("classpath:/templates/")
.addResourceLocations("file:"+upload);//本地資源路徑必須放在最上面
}
}
八、進行測試
-
初始化
-
上傳后
-
下載
-
在線預覽
-
刪除
變為初始化的樣子
有需要源碼的可以聯系我!