项目地址:

链接:https://pan.baidu.com/s/17FKxu1_09O1q4MLxRgBfKQ
提取码:szua

项目要求:

login.html:

用户名:_____
 密码:_____
    登录

showAll.html

用户:XXX

        文件id  原始名称  新文件名 文件后缀 存储路径 大小  文件类型  是否图片 下载次数      操作
          x      xxx     xxx     xxx    xxx    xx    xxx      xx     xx   下载 在线查看 删除
          
          
 上传文件:
 
选择文件________ 点击上传

要求

1.用户登陆展示用户的所有文件文件如果是图片则在页而中显示图片

2.完成文件的下载和在线打开(注意在线打开不计算为下载次数)

3.在一张页面中完成文件的上传功能,上传的目录要根据日期每天创建一个文件夹(文件夹名统一为:“yyyy-mm-dd”),上传完成后要跳转到查询所有页面

引入依赖:

<?xml version="1.0" encoding="UTF-8"?>
<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.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.sovzn</groupId>
    <artifactId>userfiles</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>userfiles</name>
    <description>文件的上传和下载</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <!--thymeleaf -->
        <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>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
      <!--  druid数据源-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.19</version>
        </dependency>
        <!--提供文件上传工具类 FileNameUtils-->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.4</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
   <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
   </build>
</project>

配置文件

spring.application.name=files
server.port=8989
server.servlet.context-path=/files

# 关闭thymeleaf的缓存
spring.thymeleaf.cache=false
# 数据库配置
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=123456
spring.datasource.url=jdbc:mysql://localhost:3306/files?characterEncoding=UTF-8&serverTimezone=UTC&useUnicode=true

# mybatis相关
mybatis.mapper-locations=classpath:/com/sovzn/mapper/*.xml
mybatis.type-aliases-package=com.sovzn.entity

#sql日志
logging.level.root=info
logging.level.com.sovzn.dao=debug

开发实体类及数据库

//用户
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Accessors(chain = true)
public class User {
    private Integer id;
    private String username;
    private String password;
}
//文件信息
@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;//用户外键
}
--建库
CREATE DATABASE `files` 
USE `files`;

--文件信息表
DROP TABLE IF EXISTS `t_files`;
CREATE TABLE `t_files` (
  `id` int(8) NOT NULL AUTO_INCREMENT COMMENT '文件id',
  `oldFileName` varchar(200) DEFAULT NULL COMMENT '文件旧名',
  `newFileName` varchar(300) DEFAULT NULL COMMENT '文件新名',
  `ext` varchar(20) DEFAULT NULL COMMENT '文件后缀',
  `path` varchar(300) DEFAULT NULL COMMENT '存储地址',
  `size` varchar(200) DEFAULT NULL COMMENT '文件大小',
  `type` varchar(120) DEFAULT NULL COMMENT '类型',
  `isImg` varchar(8) DEFAULT NULL COMMENT '是否图片',
  `downcounts` int(6) DEFAULT NULL COMMENT '下载次数',
  `uploadTime` datetime DEFAULT NULL COMMENT '上传时间',
  `userid` int(8) DEFAULT NULL COMMENT '用户id',
  PRIMARY KEY (`id`),
  KEY `user_id` (`userid`),
  CONSTRAINT `user_id` FOREIGN KEY (`userid`) REFERENCES `t_user` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8;

--用户表
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
  `id` int(8) NOT NULL,
  `username` varchar(80) DEFAULT NULL,
  `password` varchar(80) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert  into `t_user`(`id`,`username`,`password`) values (1,'sovzn','123456'),(2,'syc','123456');

开发Dao

UserDao

@Repository
public interface UserDao {
  //用户登录
    User login(User user);
}

UserFilesDao

@Repository
public interface UserFilesDao {
    //根据当前登录用户的id获取用户的文件列表
    List<UserFile> findByUserId(Integer id);
    //存贮文件信息
    void save(UserFile userFile);
    //根据文件id获取文件信息
    UserFile findById(String id);
    //更新下载次数
    void update(UserFile userFile);
    //删除文件信息
    void delete(String id);
}

开Mapper

UserDaoMapper

<?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.sovzn.dao.UserDao">

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

UserFilesDaoMapper

<?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.sovzn.dao.UserFilesDao">
    <!--根据用户id查询用户文件列表-->
<select id="findByUserId" 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" >
    INSERT INTO t_files (oldFileName, newFileName, ext, path, size, type, isImg, downcounts, uploadTime, userid)
    VALUES (#{oldFileName}, #{newFileName},#{ext},
     #{path}, #{size}, #{type}, #{isImg}, #{downcounts},
     #{uploadTime}, #{userid});
</insert>
     <!--根据id获取文件信息-->
    <select id="findById" parameterType="String" 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="String" >
        delete from t_files where id=#{id}
    </delete>
</mapper>

业务层

UserService

public interface UserService {
    User login(User user);
}

UserServiceImpl

@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

public interface UserFileService {
    //查询所有文件
    List<UserFile> findByUserId(Integer id);
    //保存文件信息
    void save(UserFile userFile);
    UserFile findById(String id);
    //更新下载次数
    void update(UserFile userFile);
    //删除文件信息
    void delete(String id);
}

UserFileServiceImpl

@Service
@Transactional
public class UserFileServiceImpl implements UserFileService {
    @Autowired
    private UserFilesDao userFilesDao;
    @Override
    public List<UserFile> findByUserId(Integer id) {
        return userFilesDao.findByUserId(id);
    }

    @Override
    public void save(UserFile userFile) {
        //是否图片  解决方案:当文件类型Type中以image开头时说明当前的类型一定为图片
         String isImg= userFile.getType().startsWith("image")?"是":"否";//判断是否类型以image开头
         userFile.setIsImg(isImg);
         userFile.setDowncounts(0);
         userFile.setUploadTime(new Date());
         userFilesDao.save(userFile);
    }

    @Override
    public UserFile findById(String id) {
        return userFilesDao.findById(id);
    }

    @Override
    public void update(UserFile userFile) {
        userFilesDao.update(userFile);
    }

    @Override
    public void delete(String id) {
        userFilesDao.delete(id);
    }
}

控制器

indexController

@Controller
public class indexController {
    @GetMapping("index")
    public String tologin(){
        return "login";//跳转到登录页
    }
}

UserController

@Controller
@RequestMapping("user")
public class UserController {
    @Autowired
    private UserService userService;

    //登录
    @PostMapping("login")
    public String login(User user, HttpSession session){
        System.out.println("进入登录");
      User u= userService.login(user);
       if (u!=null){
        session.setAttribute("user",u);
        return "redirect:/file/findAll";
       }
       else {
           return "redirect:/index";
       }
    }
}

FileController

@Controller
@RequestMapping("file")
public class FileController {
@Autowired
private UserFileService userFileService;
    //展示所有文件-----------------------------------------------------
    @GetMapping("findAll")
    public String findAll(HttpSession session, Model model){
        System.out.println("查询所有文件");
        //在session中获取用户
        User user=(User)session.getAttribute("user");
        System.out.println(user);
        List<UserFile> listfiles=userFileService.findByUserId(user.getId());
        //将得到的文件列表存入model作用域
        model.addAttribute("files",listfiles);
        return "showAll";
    }

    //上传文件,并保存文件的信息到数据库中
    @PostMapping("upload")
    //注意:下面的aaa一定要与上传文件表单中的name属性值一致,否则接收不到
    public String uploadFile(MultipartFile aaa,HttpSession session) throws IOException {

        User user = (User)session.getAttribute("user");
        // 获取文件信息--------------------------------------------

        //获取文件的原始名称
        String oldFileName=aaa.getOriginalFilename();
        //获取文件的后缀
        String ext= "."+FilenameUtils.getExtension(aaa.getOriginalFilename());
        //生成新文件名
        String newFileName=new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())+ UUID.randomUUID().toString().replace("-","+")+ext;
        // 获取文件大小
         Long  size= aaa.getSize();
         //文件类型
        String type=aaa.getContentType();

        //处理文件上传---------------------------------------------

        //获取文件存贮路径(绝对路径) 注意classpath后的:号  一般springboot项目里classpath目录指的是resources文件夹
        String realpath= ResourceUtils.getURL("classpath:").getPath()+"/static/files";
        //根据日期生成文件存储子目录
        String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());//得到当前日期
        String dateDirPath=realpath+"/"+format;
        File dateDir=new File(dateDirPath);//根据生成的dateDirPath创建文件 dateDir

        //判断dateDir是否存在,不存在就创建
        //注意:mkdirs()和mkdir()区别   mkdirs()可以创建多级目录
        if(!dateDir.exists()) {
             dateDir.mkdirs();
         }
        //文件上传
        aaa.transferTo(new File(dateDir,newFileName));
        System.out.println("开始上传文件");
        //将文件信息放入数据库中
        UserFile userFile = new UserFile();
          userFile.setOldFileName(oldFileName)
                  .setNewFileName(newFileName)
                  .setExt(ext)
                  .setSize(String.valueOf(size))
                  .setType(type)
                  .setPath("/files/"+format)
                  .setUserid(user.getId());
        userFileService.save(userFile);
        return "redirect:/file/findAll";
    }
   //文件下载-----------------------------------------------------------
    @GetMapping("download")
    public void download(String id, HttpServletResponse response) throws IOException {
        System.out.println("文件下载----");
        //获取文件信息
        UserFile userFile= userFileService.findById(id);
        //更新下载次数
        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","attachment;fileName="+ URLEncoder.encode(userFile.getOldFileName(),"UTF-8"));
        //获取响应输出流
         ServletOutputStream os= response.getOutputStream();
        //文件拷贝
        IOUtils.copy(is,os);
        //关流
        IOUtils.closeQuietly(is);
        IOUtils.closeQuietly(os);
    }
    //在线打开-----------------------------------------------------------
    @GetMapping("openinline")
    public void openinline(String id, HttpServletResponse response) throws IOException {
        System.out.println("在线打开----");
        //获取文件信息
        UserFile userFile= userFileService.findById(id);

        //根据文件信息中的文件名和文件的存储路径获取文件输入流

        //获取在线打开文件的路径(绝对路径)
        String realpath=ResourceUtils.getURL("classpath:").getPath()+"/static"+userFile.getPath();
        //获取文件输入流
        FileInputStream is = new FileInputStream(new File(realpath, userFile.getNewFileName()));
        //附件下载  (文件旧名)


        //注意:在线打开和文件下载差不多,只需将下列的attachment改为inline
        response.setHeader("content-disposition","inline;fileName="+ URLEncoder.encode(userFile.getOldFileName(),"UTF-8"));
        //获取响应输出流
        ServletOutputStream os= response.getOutputStream();
        //文件拷贝
        IOUtils.copy(is,os);
        //关流
        IOUtils.closeQuietly(is);
        IOUtils.closeQuietly(os);
    }
    @GetMapping("delete")
    //删除文件信息----------------------------------------------
   public String delete(String id) throws FileNotFoundException {
        System.out.println("删除文件");
        System.out.println(id);
        //根据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/findAll";
   }
}

页面

login.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>用户登录</title>
</head>
<body style="text-align: center">

<!--thymeleaf的语法@{}可以解析到项目根目录名(该项目名为server.servlet.context-path=/files)
,比如th:action="@{/user/login}" 在执行时,会解析为action="/files/user/login"-->

<form th:action="@{/user/login}" method="post" style="margin-top: 200px">
    <h1>欢迎访问用户文件管理系统</h1>
    Username:<input type="text" name="username" ><br/>
    Password:<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.2.1.slim.min.js}" ></script>
</head>
<body>
<h1 th:text="${'欢迎:'+session.user.username}"></h1>
<h3>文件列表</h3>
<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}==''" th:src="${#servletContext.contextPath}+${file.path}+'/'+${file.newFileName}" alt="图片">
            <span th:if="${file.isImg}==''" th:text="${file.isImg}"/>
        </td>
        <td><span th:text="${file.downcounts}"/></td>
        <td><span th:text="${file.uploadTime}"/></td>
        <td>
            <a th:href="@{/file/download(id=${file.id})}">下载</a>
            <a th:href="@{/file/openinline(id=${file.id})}">在线打开</a>
            <a th:href="@{/file/delete(id=${file.id})}">删除</a>
        </td>
    </tr>
</table>
<hr>
<h3>上传文件</h3>

<!--enctype="multipart/form-data"
不对字符编码。
在使用包含文件上传控件的表单时,必须使用该值。-->
<form th:action="@{/file/upload}" method="post" enctype="multipart/form-data">
<input type="file" name="aaa">
<input type="submit" value="上传文件">
</form>
</body>
</html>