基于SpringBoot实现文件的上传、下载和在线预览(SpringBootDemo)

在java领域中SpringBoot是一个非常好用的框架,可以快速地构建web项目,这里记录一下使用SpringBoot来实现文件的上传、下载和在线预览功能。

1.创建数据库和数据库表

本文主要用到用户和用户所属的文件,所以这里就只需要设计用户表和文件表即可。

用户表t_user

CREATE TABLE `t_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(80) DEFAULT NULL,
  `password` varchar(80) DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC

insert into t_user(username, password) values("pikacho", "123456");

文件表t_files

CREATE TABLE `t_files` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `file_name` varchar(200) DEFAULT NULL,
  `ext` varchar(20) DEFAULT NULL,
  `path` varchar(300) DEFAULT NULL,
  `size` bigint(64) DEFAULT NULL,
  `type` varchar(120) DEFAULT NULL,
  `download_counts` int(6) DEFAULT NULL,
  `upload_time` datetime DEFAULT NULL,
  `user_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `user_id` (`user_id`),
  CONSTRAINT `t_files_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `t_user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

2.创建SpringBoot项目

这里不用多说,使用IDEA创建SpringBoot项目,删除多余没用的文件,让项目结构保持简洁。

 简单地创建一个控制器,然后启动项目,测试该SpringBoot项目是否构建成功。

@Controller
public class HelloController {

    @RequestMapping("hello")
    @ResponseBody
    public String hello(){
        return "hello SpringBoot";
    }
}
 

访问项目:http://localhost:8080/hello,出现如下画面说明项目能够成功运行;先保证项目能成功运行,然后再考虑开发功能。

3.添加该项目需要的依赖以及配置基本环境

pom.xml依赖

       <dependencies>
        <!-- thymeleaf模板引擎的依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <!-- SpringBoot的web项目依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- lombok依赖,作用是创建实体类时不用自己手动添加构造器,setter等方法-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!--mybatis依赖-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.0</version>
        </dependency>

        <!--数据库连接-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!--shiro-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.1</version>
        </dependency>

        <!-- 文件上传依赖-->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.4</version>
        </dependency>

         <!-- druid数据库连接池依赖-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.19</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

application.yml主配置文件

spring:
  application:
    name: fileStorage
  thymeleaf:
    cache: false
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/fileservice?serverTimezone=Asia/Shanghai&userUnicode=true&characterEncoding=utf-8
    username: root
    password: root

  server:
    port: 8080


  mybatis:
    mapper-locations: classpath:mybatis/mapper/*.xml
    type-aliases-package: com.pikacho.entity

添加完依赖以及将主配置文件配置完成,完成本项目功能需要的基本环境就已经全部搭建完成了,启动项目测试项目是否可以正常运行;出现下面的画面说明项目基本环境搭建成功。

4.用户登录、注销及注册功能

4.1.完成登录功能

即使一个非常简单的demo项目,也是少不了前端页面。对于一个后端开发者来说,要自己去写前端页面布局和样式是一件挺痛苦也困难的事(是真的不会写啊!)。所以这里使用layui框架来快速构建前端页面。当然,这只是简单的使用一下该框架,想要熟练使用。还需继续深入学习才行。

1.引入layui

将layui需要的文件添加到static文件夹下

 2.创建登录页面

login.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <title>login</title>
    <link rel="stylesheet" th:href="@{/css/layui.css}">
</head>
<body>

<div class="layui-container">
    <div class="layui-row" style="margin-top: 80px;">
        <div class="layui-col-lg4 layui-col-lg-offset4">
            <h1 style="margin:20px; text-align: center"> 请 登 录 </h1>
            <form class="layui-form" th:action="@{/user/login}" , method="post">
                <div class="layui-form-item">
                    <p style="color: red; text-align: center" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>
                </div>
                <div class="layui-form-item">
                    <label class="layui-form-label">用户名</label>
                    <div class="layui-input-block">
                        <input class="layui-input" type="text" name="username" required autocomplete="false">
                    </div>
                </div>
                <div class="layui-form-item">
                    <label class="layui-form-label">密  码</label>
                    <div class="layui-input-block">
                        <input class="layui-input" type="password" name="password" required autocomplete="false">
                    </div>
                </div>
                <div class="layui-form-item">
                    <div class="layui-input-block">
                        <button class="layui-btn" lay-submit lay-filter="formDemo">立即登录</button>
                        <button type="reset" class="layui-btn layui-btn-primary">重置</button>
                    </div>
                </div>
            </form>
            <div style="float:right">
                <a th:href="@{/user/toRegister}">去注册</a>
            </div>
        </div>
    </div>
</div>

<script th:src="@{/layui.js}"></script>
<script>
    //一般直接写在一个js文件中
    layui.use(['layer', 'form'], function(){
        var layer = layui.layer
            ,form = layui.form;
    });
</script>
</body>
</html>

UserController.java

    /**
     * 前往登录页面
     * @return
     */
    @RequestMapping("toLogin")
    public String toLogin(){
        return "login";
    }

这样,之后我们就可以轻松地创建前端页面了,并且不用自己去设计样式和布局等问题。还是要提一下,像这样简单使用一下这种程度就够了,但是要熟练使用的话,就要更加深入学习才行。

3.完成登录功能

  • 创建User实体类--User.java
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class User {
    
    private Integer id;
    private String username;
    private String password;
}
  • 创建UserDao及其mapper映射文件--UserDao.java & UserDaoMapper.xml

@Mapper
@Repository
public interface UserDao {

    /**
     * 用户登录功能
     * @return
     */
    public User login(User user);


}
<?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.pikacho.dao.UserDao">
    <!-- public User login(User user)-->
    <select id="login" parameterType="User" resultType="User">
        select id, username, password
        from t_user
        where username = #{username} and password = #{password};
    </select>

  • 创建UserService类及其实现类--UserService.java & UserServiceImpl.java

public interface UserService {
    public User login(User user);
}
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    public UserDao userDao;

    @Override
    public User login(User user){
        return userDao.login(user);
    }
}
  • 利用Shiro框架实现登录认证功能

Shiro框架可以快速实现登录认证等安全权限功能,这里也是简单使用一下,想要深入理解使用还需查阅其官方文档。

UserRealm.java

public class UserRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;


    // 授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection){
        return null;
    }

    // 认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken)token;

        User user = new User();
        user.setUsername(usernamePasswordToken.getUsername());
        user.setPassword(String.valueOf(usernamePasswordToken.getPassword()));
        // 从数据库查询出来
        User userDB = userService.login(user);
        if(userDB == null){
            return null;
        }

        return new SimpleAuthenticationInfo(userDB, user.getPassword(), "");

    }
}

ShiroConfig.java

@Configuration
public class ShiroConfig {

    // 第一步:创建UserRealm对象
    @Bean
    public UserRealm userRealm(){
        return new UserRealm();
    }

    // 第二步:创建默认安全管理器DefaultWebSecurityManager
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(
            @Qualifier("userRealm") UserRealm userRealm ){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(userRealm);
        return securityManager;
    }

    // 第三步:创建ShiroFilterFactoryBean
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(
            @Qualifier("securityManager") DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        // 设置安全管理器
        bean.setSecurityManager(securityManager);
        /*
        *   anon: 无需认证就能访问
            authc: 必须认证后才能访问
            user: 必须拥有 记住我 功能才能用
            perms: 拥有对某个资源的权限才能访问
            role: 拥有某个角色权限才能访问
         */

        // 拦截/file/* ,该路径只有登录的情况下才能查看
        Map<String, String> filterMap = new LinkedHashMap<>();
        filterMap.put("/file/*", "authc");
        bean.setFilterChainDefinitionMap(filterMap);

        // 设置没有访问权限时,跳转页面
        bean.setLoginUrl("/login");
        return bean;
    }
}
  • 在UserController类中添加登录方法
    @PostMapping("login")
    public String login(User user, Model model){
        Subject subject = SecurityUtils.getSubject();
        // 封装用户信息
        UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());
        try{
            subject.login(token);
            Session session = subject.getSession();
            session.setAttribute("user", (User)subject.getPrincipal());
            // 前往文件列表页面
            return "list";
        }catch (UnknownAccountException e){
            model.addAttribute("msg", "用户名或密码错误");
            return "login";
        }catch (IncorrectCredentialsException e){
            model.addAttribute("msg", "用户名或密码错误");
            return "login";
        }
    }
  • 最后在SpringbootFileuploadApplication类上添加包扫描注解,不然mybatis无法将接口和xml配置文件绑定起来
@SpringBootApplication
@MapperScan(basePackages = "com.pikacho.dao")
public class SpringbootFileuploadApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootFileuploadApplication.class, args);
    }

}

登录功能代码已经开发完毕了,现在测试一下功能是否正常。 

访问项目:http://localhost:8080/user/toLogin,之前创建用户表时,就已经创建了一个用户。用户名:pikacho  密码:123456。

 

 4.2.完成注册功能

1.创建注册页面

register.html

<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <title>register</title>
    <link rel="stylesheet" th:href="@{/css/layui.css}">

</head>
<body>
<div class="layui-container">
    <div class="layui-row" style="margin-top: 80px;">
        <div class="layui-col-lg4 layui-col-lg-offset4">
            <h1 style="margin:20px; text-align: center"> 请 注 册 </h1>
            <div class="layui-form-item">
                <p style="color: red; text-align: center" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>
            </div>
            <form class="layui-form" th:action="@{/user/register}" method="post">
                <div class="layui-form-item">
                    <label class="layui-form-label">用户名</label>
                    <div class="layui-input-block">
                        <input  class="layui-input" type="text" name="username" required>
                    </div>
                </div>
                <div class="layui-form-item">
                    <label class="layui-form-label">密  码</label>
                    <div class="layui-input-block">
                        <input class="layui-input" type="password" name="password" required autocomplete="false">
                    </div>
                </div>
                <div class="layui-form-item">
                    <div class="layui-input-block">
                        <button class="layui-btn" lay-submit lay-filter="formDemo">立即注册</button>
                        <button type="reset" class="layui-btn layui-btn-primary">重置</button>
                    </div>
                </div>
            </form>
            <div style="float:right">
                <a th:href="@{/user/toLogin}">去登录</a>
            </div>
        </div>
    </div>
</div>
<script th:src="@{/layui.js}"></script>
<script>
    //一般直接写在一个js文件中
    layui.use(['layer', 'form'], function(){
        var layer = layui.layer
            ,form = layui.form;
    });

</script>



</body>
</html>

2.完成注册功能

  • 在UserDao类中添加register(),编写mapper映射文件
    /**
     *
     * @param user
     */
    public void register(User user);
    <!-- 注册-->
    <insert id="register" parameterType="User">
        insert into t_user (username, password)
        values(#{username}, #{password});
    </insert>
  • 在UserService类及实现类中添加注册方法
    /**
     *
     * @param user
     */
    public void register(User user);
    /**
     *
     * @param user
     */
    @Override
    public void register(User user){
        userDao.register(user);
    }
  • 在UserController类中添加注册逻辑

测试注册功能, 访问项目:http://localhost:8080/user/toRegister ;添加用户pikacho2 :123456

 

 

4.3.创建list页面

前面只是简单的创建一个list页面验证登录功能,现在补全list页面。

list.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <title>FileList</title>
    <link rel="stylesheet" th:href="@{/css/layui.css}">
</head>

<body>
<div class="layui-fluid">
    <nav class="layui-nav">
        <div class="layui-nav-item">
            <p class="layui-nav-title" style="font-size: larger">
                欢迎:<span th:if="${session.user!=null}" th:text="${session.user.username}"/>
            </p>
        </div>
        <div class="layui-nav-item" style="float: right;">
            <button class="layui-btn">
                <a th:href="@{/user/logout}" style="font-size: larger; padding: 0px; color: white">login out</a>
            </button>
        </div>
        <div class="layui-nav-item" style="float: right; padding-right: 20px">
            <button type="button" class="layui-btn" id="fileUpload">
                上传文件
            </button>
        </div>
    </nav>

    <!-- 文件列表-->
    <table id="fileList" lay-filter="fileTable"></table>

    <script type="text/html" id="optBar">
        <a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="download">下载</a>
        <a class="layui-btn layui-btn-xs" lay-event="preview">预览</a>
        <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="delete">删除</a>
    </script>

</div>
<script th:src="@{/layui.js}" charset="utf-8"></script>

</body>
</html>

 4.4.完成注销功能

  • 在UserController类中添加注销方法
    /**
     * 注册功能
     * @return
     */
    @GetMapping("logout")
    public String logout(){
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        // 这里需要注意:redirect:user/toLogin 实际的请求路径http://localhost:8080/user/user/toLogin
        // 所以需要使用redirect:toLogin
        return "redirect:toLogin"; 
    }

5.文件的展示、上传、删除、下载功能

5.1.文件的展示

  • 创建文件实例类--UserFile.java
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
@Accessors(chain = true)
public class UserFile {
    private Integer id;
    private String fileName;
    private String ext;
    private String path;
    private long size;
    private String type;
    private Integer downloadCounts;
    private Date uploadTime;
    private Integer userId;
}
  • 创建UserFileDao及其mapper映射文件
@Mapper
@Repository
public interface UserFileDao {

    /**
     * 根据用户id获得用户文件列表
     * @param id
     * @param begin
     * @param offset
     * @return
     */
    public List<UserFile> queryByUserId(Integer id, Integer begin, int offset);


    /**
     * 根据用户id获得该用户文件总数
     * @param id
     * @return
     */
    public int queryFileCount(Integer id);
}
<?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.pikacho.dao.UserFileDao">
    <resultMap id="UserFileMap" type="UserFile">
        <!-- 只需要映射列名和属性名不一致的-->
        <id column="id" property="id"></id>
        <result column="file_name" property="fileName"></result>
        <result column="download_counts" property="downloadCounts"></result>
        <result column="upload_time" property="uploadTime"></result>
        <result column="user_id" property="userId"></result>
    </resultMap>

    <!-- 根据用户id查询文件列表-->
    <select id="queryByUserId" parameterType="Integer" resultMap="UserFileMap">
        select * from t_files
        where user_id = #{id}
        order by id
        limit #{begin}, #{offset};
    </select>
     <!-- 根据用户id查询文件数量-->
    <select id="queryFileCount" parameterType="Integer" resultType="Integer">
        select count(*) from t_files
        where user_id = #{id};
    </select>
</mapper>
  • 创建UserFileService类及其实现类
public interface UserFileService {

    /**
     * 根据用户id获得文件列表
     * @param id
     * @param page
     * @param limit
     * @return
     */
    public List<UserFile> queryByUserId(Integer id, Integer page, Integer limit);

    /**
     * 根据用户id获得文件数
     * @param id
     * @return
     */
    public int queryFileCounts(Integer id);
}
@Service
public class UserFileServiceImpl implements UserFileService {
    @Autowired
    private UserFileDao userFileDao;

    /**
     * 根据用户id获得文件列表
     * @param id
     * @param page
     * @param limit
     * @return
     */
    @Override
    public List<UserFile> queryByUserId(Integer id, Integer page, Integer limit){
        // page表示第几页,limit表示每页显示多少行数据
        int begin = (page-1)*limit;   // 该计算方法获得开始的位置
        int offset = limit;
        return userFileDao.queryByUserId(id, begin, limit);
    }

    /**
     * 根据用户id获得文件数
     * @param id
     * @return
     */
    @Override
    public int queryFileCounts(Integer id){
        return userFileDao.queryFileCounts(id);
    }
}
  • 创建UserFileController类
@Controller
@RequestMapping("file")
public class UserFileController {
    @Autowired
    private UserFileService userFileService;

    /**
     * 返回文件列表
     * @param session
     * @param request
     * @return
     */
    @PostMapping("all")
    @ResponseBody
    public Map<String, Object> queryAllFile(HttpSession session, HttpServletRequest request){
        int page = Integer.parseInt(request.getParameter("page"));
        int limit = Integer.parseInt(request.getParameter("limit"));
        User user = (User) session.getAttribute("user");
        List<UserFile> files = userFileService.queryByUserId(user.getId(), page, limit);

        Map<String, Object> res = new HashMap<>();
        res.put("code", 0);
        res.put("count", userFileService.queryFileCounts(user.getId()));
        res.put("data", files);
        return res;
    }

}
  • 接着在list.html中添加渲染表格的脚本
        // 渲染表格
        table.render({
            elem: '#fileList',
            height: 600,
            minWidth: 80,
            url: '/file/all',    // 这一定要是/file/all,之前我是file/all不停的报错,无法访问成功
            parseData: function (res) {
                            return {
                                "code": res.code,
                                "msg": "",
                                "count": res.count,
                                "data": res.data
                            };
            },
            method: 'post',
            limit: 10,
            page: true,
            cols: [[
                {field:'id', title:'ID', sort:true, fixed:'left'},
                {field:'fileName', title:'文件名'},
                {field:'ext', title:'文件后缀'},
                {field:'path', title:"存储路径"},
                {field:'size', title:'大小'},
                {field:'type', title:"类型"},
                {field:'downloadCounts', title:'下载次数'},
                {field:'uploadTime', title:'上传时间'},
                {tilte:'操作',align:'center', toolbar:'optBar', width:200, fixed:'right'}
            ]]
        });

5.2.文件上传

  • 在UserFileDao类中添加上传文件方法及mapper映射文件
    /**
     * 上传文件
     * @param userFile
     */
    public void save(UserFile userFile);
    <!-- 上传文件-->
    <insert id="save" parameterType="UserFile" useGeneratedKeys="true" keyProperty="id">
        insert into t_files(file_name, ext, path, size, type, download_counts, upload_time, user_id)
        values(#{fileName}, #{ext}, #{path}, #{size}, #{type}, #{downloadCounts}, #{uploadTime}, #{userId});
    </insert>
  • 在UserFileService类及UserFileServiceImpl类中添加方法
    /**
     * 上传文件
     * @param userFile
     */
    public void save(UserFile userFile);



    /**
     * 上传文件
     * @param userFile
     */
    @Override
    public void save(UserFile userFile){
        userFile.setDownloadCounts(0).setUploadTime(new Date());
        userFileDao.save(userFile);
    }
  • 在UserFileController类中添加上传文件接口
    @GetMapping("index")
    public String fileIndex(){
        return "list";
    }


    /**
     * 上传文件
     * @param file
     * @param session
     * @return
     */
    @PostMapping("upload")
    @ResponseBody
    public Map<String, String> uploadFile(@RequestParam("file")MultipartFile file, HttpSession session){
        Map<String, String> res = new HashMap<>();
        try{
            User user = (User) session.getAttribute("user");
            String fileName = file.getOriginalFilename();
            String extension = FilenameUtils.getExtension(fileName);
            long size = file.getSize();
            String type = file.getContentType();
            // 根据日期生成目录
            String localContainer = "/fileContainer";
            String uploadPath = ResourceUtils.getURL("classpath").getPath()+localContainer;
            String dateFormat = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
            File dateDirPath = new File(uploadPath+File.separator+dateFormat);
            if(!dateDirPath.exists()){
                dateDirPath.mkdirs();
            }

            file.transferTo(new File(dateDirPath, fileName));
            // 将文件信息存入数据库
            UserFile userFile = new UserFile();
            userFile.setFileName(fileName)
                    .setExt('.'+extension)
                    .setPath(Paths.get(localContainer, dateFormat, fileName).toString())
                    .setSize(size)
                    .setType(type)
                    .setUserId(user.getId());

            userFileService.save(userFile);

            res.put("code", "0");
            res.put("msg", "上传成功");
            res.put("url", "/file/index");

        }catch(IOException e){
            res.put("code", "-1");
            res.put("msg", "上传失败");
            res.put("url", "/file/index");
        }
        return res;
    }

 

这里文件存储在我的本地磁盘上,文件表中存储的是文件在我磁盘存储的存储路径。

5.3.文件下载

开发流程与上面基本一致。

 // UserFiledao
   /**
     * 下载文件
     * @param id
     * @return
     */
    public UserFile queryByUserFileId(Integer id);

    /**
     * 更新文件下载次数
     * @param userFile
     */
    public void update(UserFile userFile);


// UserFileService
    /**
     * 下载文件
     * @param id
     * @return
     */
    public UserFile queryByUserFileId(Integer id);

    /**
     * 跟新文件下载次数
     * @param userFile
     */
    public void update(UserFile userFile);

// UserFileServiceImpl
    /**
     * 下载文件
     * @param id
     * @return
     */
    @Override
    public UserFile queryByUserFileId(Integer id) {
        return userFileDao.queryByUserFileId(id);
    }

    /**
     * 跟新文件下载次数
     * @param userFile
     */
    @Override
    public void update(UserFile userFile) {
        userFileDao.update(userFile);
    }
    <!-- 下载文件-->
    <select id="queryByUserFileId" parameterType="Integer" resultMap="UserFileMap">
        select * from t_files where id = #{id};
    </select>
    <!-- 更新文件下载次数-->
    <update id="update" parameterType="UserFile">
        update t_files set download_counts = #{downloadCounts} where id = #{id};
    </update>
    /**
     * 下载文件
     * @param id
     * @param response
     */
    @GetMapping("download/{id}")
    public void download(@PathVariable("id") Integer id, HttpServletResponse response){
        String openStyle = "attachment";
        try{
            getFile(openStyle, id, response);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 更新文件下载次数
     * @param openStyle
     * @param id
     * @param response
     * @throws Exception
     */
    public void getFile(String openStyle, Integer id, HttpServletResponse response) throws Exception {
        UserFile userFile = userFileService.queryByUserFileId(id);
        String realPath = ResourceUtils.getURL("classpath").getPath()+userFile.getPath();

        FileInputStream is = new FileInputStream(new File(realPath));
        // 附件下载
        response.setHeader("content-disposition", openStyle+";filename=" + URLEncoder.encode(userFile.getFileName(), "UTF-8"));
        // 获取响应response输出流
        ServletOutputStream os = response.getOutputStream();
        // 文件拷贝
        IOUtils.copy(is, os);
        IOUtils.closeQuietly(is);
        IOUtils.closeQuietly(os);

        if(openStyle.equals("attachment")){
            userFile.setDownloadCounts(userFile.getDownloadCounts()+1);
            userFileService.update(userFile);
        }
    }

list.html

        //监听工具条
        table.on('tool(fileTable)', function (obj) {
            var data = obj.data;
            if (obj.event === 'download') {
                window.open("/file/download/" + data.id);
                obj.update({
                    "downloadCounts": data.downloadCounts + 1
                });
            } else if (obj.event === 'delete') {
                layer.confirm('真的删除文件吗?', function (index) {
                    $.ajax({
                        url: "/file/delete/" + data.id,
                        type: "Get",
                        success: function (res) {
                            layer.msg(res.msg);
                            obj.del();
                        },
                        error: function (res) {
                            $.message.alert('msg', res.msg);
                        }
                    });
                    layer.close(index);
                });
            } else if (obj.event === 'preview') {
                
                layer.open({
                    type: 2,
                    skin: 'layui-layer-demo', //样式类名
                    title: '文件预览',
                    closeBtn: 1, //显示关闭按钮
                    anim: 2,
                    area: ['893px', '600px'],
                    shadeClose: true, //开启遮罩关闭
                    content: '/file/preview/' + data.id
                });
            }
        });

 5.4.文件删除

文件删除开发流程也是同上。

6.完成文件预览功能

  • 添加预览方法

    /**
     * 文件预览
     * @param id
     * @param response
     * @throws IOException
     */
    @GetMapping("preview/{id}")
    public void preview(@PathVariable("id") Integer id, HttpServletResponse response) throws Exception {
        String openStyle = "inline";
        getFile(openStyle,id,response);
    }

到此,这个小项目就基本完成。

demo源码地址https://github.com/picacho-pkq/SpringBoot-demo

demo下载地址https://download.csdn.net/download/pikcacho_pkq/75146243

  • 19
    点赞
  • 143
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

picacho_pkq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值