Springboot+Mybatis+ajax实现文件上传下载功能

这里使用的是单机版的文件上传下载功能,如果是搞分布式,建议直接使用FastDFS
1.新建一个Springboot项目,在pom.xml中导入如下依赖


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0modelVersion>
  <parent>
      <groupId>org.springframework.bootgroupId>
      <artifactId>spring-boot-starter-parentartifactId>
      <version>2.2.5.RELEASEversion>
      <relativePath/> 
  parent>
  <groupId>com.cdgroupId>
  <artifactId>springboot_filesartifactId>
  <version>0.0.1-SNAPSHOTversion>
  <name>springboot_filesname>
  <description>Demo project for Spring Bootdescription>

  <properties>
      <java.version>1.8java.version>
  properties>

  <dependencies>
      <dependency>
          <groupId>org.springframework.bootgroupId>
          <artifactId>spring-boot-starter-thymeleafartifactId>
      dependency>
      <dependency>
          <groupId>org.springframework.bootgroupId>
          <artifactId>spring-boot-starter-webartifactId>
      dependency>
      <dependency>
          <groupId>org.mybatis.spring.bootgroupId>
          <artifactId>mybatis-spring-boot-starterartifactId>
          <version>2.1.4version>
      dependency>

      <dependency>
          <groupId>com.alibabagroupId>
          <artifactId>druidartifactId>
          <version>1.1.19version>
      dependency>

      
      <dependency>
          <groupId>commons-fileuploadgroupId>
          <artifactId>commons-fileuploadartifactId>
          <version>1.4version>
      dependency>


      <dependency>
          <groupId>org.springframework.bootgroupId>
          <artifactId>spring-boot-devtoolsartifactId>
          <scope>runtimescope>
          <optional>trueoptional>
      dependency>
      <dependency>
          <groupId>mysqlgroupId>
          <artifactId>mysql-connector-javaartifactId>
          <scope>runtimescope>
      dependency>
      <dependency>
          <groupId>org.projectlombokgroupId>
          <artifactId>lombokartifactId>
          <optional>trueoptional>
      dependency>
      <dependency>
          <groupId>org.springframework.bootgroupId>
          <artifactId>spring-boot-starter-testartifactId>
          <scope>testscope>
      dependency>
  dependencies>

  <build>
      <plugins>
          <plugin>
              <groupId>org.springframework.bootgroupId>
              <artifactId>spring-boot-maven-pluginartifactId>
          plugin>
      plugins>
  build>

project>

2.在static目录下面添加进去jquery的包,如下图所示
Springboot+Mybatis+ajax实现文件上传下载功能_第1张图片
3.使用Navicat创建两张表,一张用户表,一张文件表,在这里说明一下,一个用户可以上传和下载多个多个文件,多个文件也可以是同一个用户的,因此这里,用户和文件是出于一对多的关系,建表如下
文件表
Springboot+Mybatis+ajax实现文件上传下载功能_第2张图片
4. 对应的pojo层实体类代码如下

package com.cd.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.experimental.Accessors;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
@ToString
public class User {

    private Integer id;
    private String username;
    private String password;

}
##2## 文件表对应实体类
package com.cd.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.experimental.Accessors;

import java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
@ToString
public class UserFile {

    private Integer id;  //文件的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;  //用户外键
}

5. 对应dao层

package com.cd.dao;

import com.cd.pojo.User;
import org.springframework.stereotype.Component;

@Component
public interface UserDao {
       //通过用户名和密码封装成一个对象去查询数据库
    User login(User user);
}
package com.cd.dao;


import com.cd.pojo.UserFile;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public interface UserFileDao {
      // 根据登陆用户的id查询文件列表
   List<UserFile> fingByUserId(Integer id);
        //保存文件到数据库
    void save(UserFile userFile);
        // 通过id找到要下载的文件
    UserFile findById(Integer id);
         // 更新了下载次数
    void update(UserFile userFile);
        // 删除数据库中的文件数据
    void delete(Integer id);
}

6.对应业务service层(UserService)

package com.cd.service;
import com.cd.pojo.User;
public interface UserService {
     //通过用户名和密码封装成一个对象去查询数据库
     User login(User user);  
}

对应实现类(UserServiceImpl)

package com.cd.service;

import com.cd.dao.UserDao;
import com.cd.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional
public class UserServiceImpl implements UserService {
         @Autowired
      private UserDao userDao;
           // 登陆
    @Override
    @Transactional(propagation = Propagation.SUPPORTS)
    public User login(User user) {
        return userDao.login(user);
    }
}

对应UserFileService

package com.cd.service;
import com.cd.pojo.UserFile;
import java.util.List;
public interface UserFileService {

    // 根据登陆用户的id查询文件列表
    List<UserFile> fingByUserId(Integer id);
       // 保存文件到数据库
    void save(UserFile userFile);
       //通过id找到要下载的文件
    UserFile findById(Integer id);
      // 更新了下载次数
    void update(UserFile userFile);
       // 删除数据库中的文件
    void delete(Integer id);
}

对应实现类(UserFileServiceImpl)

package com.cd.service;
import com.cd.dao.UserFileDao;
import com.cd.pojo.UserFile;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List;

@Service
@Transactional
public class UserFileServiceImpl implements UserFileService {
            @Autowired
        private UserFileDao userFileDao;

         // 通过用户id查询文件信息
    @Override
    public List<UserFile> fingByUserId(Integer id) {
        return userFileDao.fingByUserId(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);
    }

       //  通过id找到要下载的文件
    @Override
    public UserFile findById(Integer id) {
        return userFileDao.findById(id);
    }
    
        //更新了下载次数
    @Override
    public void update(UserFile userFile) {
          userFileDao.update(userFile);
    }

        // 删除数据库中的文件数据
    @Override
    public void delete(Integer id) {
        userFileDao.delete(id)  ;
    }
} 

7. mapper配置文件如下
UserDaoMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cd.dao.UserDao">

      
    <select id="login" parameterType="User" resultType="User">
         select id,username,password
         from t_user
         where username=#{username}
         and password=#{password}
    select>  
mapper>

UserFileDaoMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cd.dao.UserFileDao">

      
    <select id="fingByUserId" parameterType="Integer" resultType="UserFile">
         select id,oldFileName,newFileName,ext,path,size,type,isImg,downcounts,uploadTime,userId
         from t_files
         where userid=#{id}
    select>

      
    <insert id="save" parameterType="UserFile" useGeneratedKeys="true" keyProperty="id">
          insert into t_files
          values (#{id},#{oldFileName},#{newFileName},#{ext},#{path},#{size},
          #{type},#{isImg},#{downcounts},#{uploadTime},#{userId})
    insert>

        
      <select id="findById" parameterType="Integer" resultType="UserFile">
          select id,oldFileName,newFileName,ext,path,size,type,isImg,downcounts,uploadTime,userId
          from t_files
          where id = #{id}
      select>

         
      <update id="update" parameterType="UserFile">
          update t_files set downcounts=#{downcounts} where id = #{id}
      update>

        
      <delete id="delete" parameterType="Integer">
          delete from t_files where id = #{id}
      delete>
mapper>

8. controller层
1.FileController ,该层主要用来处理用户文件上传,下载,删除,展示等这些请求

    package com.cd.controller;

import com.cd.pojo.User;
import com.cd.pojo.UserFile;
import com.cd.service.UserFileService;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.*;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.UUID;

@Controller
@RequestMapping("files")
public class FileController {


       @Autowired
       private UserFileService userFileService;
       
    /**
     * 返回当前用户的所有文件列表---json格式
     */
        @GetMapping("findAllJson")
        @ResponseBody
        public List<UserFile> findAllJson(HttpSession session,Model model){
               // 在登陆的用户中获取用户的id
            User user = (User)session.getAttribute("user");
                 // 根据用户id查询的文件信息
            List<UserFile> userFiles = userFileService.fingByUserId(user.getId());
             return userFiles ;
        }


    /**
     * 上传文件处理,并保存文件信息到数据库中
     */
    @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 = realPath + "/" + 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:/files/showAll" ;
    }

    /**
     *   文件下载
     * @param id
     */
    @GetMapping("/download")
           public void download(String openStyle,Integer 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.fingByUserId(user.getId());
               //存入作用域中
             model.addAttribute("files",userFiles);
            return "showAll"  ;
     }

    /**
     *  删除文件信息
     * @param id
     * @return
     */
    @GetMapping("delete")
         public String delete(Integer 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:/files/showAll";
    }
}
 2.UserController 用来处理用户登录跳转
 package com.cd.controller;
import com.cd.pojo.User;
import com.cd.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpSession;
@Controller
@RequestMapping("user")
public class UserController {

        @Autowired
     private UserService userService;
    /**
     *  登陆方法
     * @param user
     * @param session
     * @return
     */
    @PostMapping("login")
    public String login(User user, HttpSession session){
            User userDB = userService.login(user);
            if(userDB!=null){
               session.setAttribute("user",userDB);
                 return "redirect:/files/showAll";
            }else {
                return "redirect:/index";
            }
        }
}

indexController: 用来处理跳转到首页请求

package com.cd.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class IndexController {

    @GetMapping("index")
   public String toLogin(){
        return "login";
    }
}

application.properties配置文件

spring.application.name=files
server.port=8080
server.servlet.context-path=/files
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.url=jdbc:mysql://localhost:3306/userfiles?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
mybatis.type-aliases-package=com.cd.pojo
mybatis.mapper-locations=classpath:/mapper/*.xml

10 template目录下的代码如下(thymeleaf)
login.html

        <!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">
    用户名:<input type="username" name="username">  <br/>
    密码:  <input type="password" name="password">  <br/>
            <input type="submit" value="登录">
    </form>

</body>
</html>

showAll.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>用户文件列表展示页面</title>
    <script th:src="@{/js/jquery-3.3.1.min.js}"></script>
    <script>
          $(function () {
              var time;
              $("#start").click(function () {
                time = setInterval(function () {
                      $.get("[[@{/files/findAllJson}]]",function (res) {
                          // 遍历
                          $.each(res,function (index,file) {
                              $("#"+file.id).text(file.downcounts);
                          })
                      }) ;
                  },3000) ;
              });
              
              $("#stop").click(function () {
                  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>                                  <!--th:src="@{/}+'/'+ ${file.path}+'/'+${file.newFileName}"-->
                <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="@{/files/download(id=${file.id})}">下载</a>
                <a th:href="@{/files/download(id=${file.id},openStyle='inline')}">在线打开</a>
                <a th:href="@{/files/delete(id=${file.id})}">删除</a>
            </td>
        </tr>
    </table>
<hr>
<h3>上传文件</h3>
<form th:action="@{/files/upload}" method="post" enctype="multipart/form-data">
    <input type="file" name="aaa"> <input type="submit" value="上传文件">
</form>
</body>
</html>

最后,启动springboot项目,访问:localhost:8080/files/index 简略效果图如下所示
Springboot+Mybatis+ajax实现文件上传下载功能_第3张图片

你可能感兴趣的:(springboot,java,mybatis,spring,boot)