Commit 629fa9b40732d807cb12fdc7f5279460cd17d55a

Authored by YunaiV
1 parent f942b34d

1. 基于 db 实现文件的存储

Showing 25 changed files with 331 additions and 148 deletions
ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java deleted
1   -package com.ruoyi.web.controller.common;
2   -
3   -import javax.servlet.http.HttpServletRequest;
4   -import javax.servlet.http.HttpServletResponse;
5   -import org.slf4j.Logger;
6   -import org.slf4j.LoggerFactory;
7   -import org.springframework.beans.factory.annotation.Autowired;
8   -import org.springframework.http.MediaType;
9   -import org.springframework.web.bind.annotation.GetMapping;
10   -import org.springframework.web.bind.annotation.PostMapping;
11   -import org.springframework.web.bind.annotation.RestController;
12   -import org.springframework.web.multipart.MultipartFile;
13   -import com.ruoyi.common.config.RuoYiConfig;
14   -import com.ruoyi.common.constant.Constants;
15   -import com.ruoyi.common.core.domain.AjaxResult;
16   -import com.ruoyi.common.utils.StringUtils;
17   -import com.ruoyi.common.utils.file.FileUploadUtils;
18   -import com.ruoyi.common.utils.file.FileUtils;
19   -import com.ruoyi.framework.config.ServerConfig;
20   -
21   -/**
22   - * 通用请求处理
23   - *
24   - * @author ruoyi
25   - */
26   -@RestController
27   -public class CommonController
28   -{
29   - private static final Logger log = LoggerFactory.getLogger(CommonController.class);
30   -
31   - @Autowired
32   - private ServerConfig serverConfig;
33   -
34   - /**
35   - * 通用下载请求
36   - *
37   - * @param fileName 文件名称
38   - * @param delete 是否删除
39   - */
40   - @GetMapping("common/download")
41   - public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request)
42   - {
43   - try
44   - {
45   - if (!FileUtils.checkAllowDownload(fileName))
46   - {
47   - throw new Exception(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName));
48   - }
49   - String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1);
50   - String filePath = RuoYiConfig.getDownloadPath() + fileName;
51   -
52   - response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
53   - FileUtils.setAttachmentResponseHeader(response, realFileName);
54   - FileUtils.writeBytes(filePath, response.getOutputStream());
55   - if (delete)
56   - {
57   - FileUtils.deleteFile(filePath);
58   - }
59   - }
60   - catch (Exception e)
61   - {
62   - log.error("下载文件失败", e);
63   - }
64   - }
65   -
66   - /**
67   - * 通用上传请求
68   - */
69   - @PostMapping("/common/upload")
70   - public AjaxResult uploadFile(MultipartFile file) throws Exception
71   - {
72   - try
73   - {
74   - // 上传文件路径
75   - String filePath = RuoYiConfig.getUploadPath();
76   - // 上传并返回新文件名称
77   - String fileName = FileUploadUtils.upload(filePath, file);
78   - String url = serverConfig.getUrl() + fileName;
79   - AjaxResult ajax = AjaxResult.success();
80   - ajax.put("fileName", fileName);
81   - ajax.put("url", url);
82   - return ajax;
83   - }
84   - catch (Exception e)
85   - {
86   - return AjaxResult.error(e.getMessage());
87   - }
88   - }
89   -
90   - /**
91   - * 本地资源通用下载
92   - */
93   - @GetMapping("/common/download/resource")
94   - public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response)
95   - throws Exception
96   - {
97   - try
98   - {
99   - if (!FileUtils.checkAllowDownload(resource))
100   - {
101   - throw new Exception(StringUtils.format("资源文件({})非法,不允许下载。 ", resource));
102   - }
103   - // 本地资源路径
104   - String localPath = RuoYiConfig.getProfile();
105   - // 数据库资源地址
106   - String downloadPath = localPath + StringUtils.substringAfter(resource, Constants.RESOURCE_PREFIX);
107   - // 下载名称
108   - String downloadName = StringUtils.substringAfterLast(downloadPath, "/");
109   - response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
110   - FileUtils.setAttachmentResponseHeader(response, downloadName);
111   - FileUtils.writeBytes(downloadPath, response.getOutputStream());
112   - }
113   - catch (Exception e)
114   - {
115   - log.error("下载文件失败", e);
116   - }
117   - }
118   -}
ruoyi-ui/src/api/login.js
... ... @@ -34,7 +34,7 @@ export function logout() {
34 34 // 获取验证码
35 35 export function getCodeImg() {
36 36 return request({
37   - url: '/captcha/get-image',
  37 + url: '/system/captcha/get-image',
38 38 method: 'get'
39 39 })
40 40 }
... ...
ruoyi-ui/src/api/system/post.js
... ... @@ -56,6 +56,7 @@ export function exportPost(query) {
56 56 return request({
57 57 url: '/system/post/export',
58 58 method: 'get',
59   - params: query
  59 + params: query,
  60 + responseType: 'blob'
60 61 })
61 62 }
... ...
ruoyi-ui/src/views/system/post/index.vue
... ... @@ -286,7 +286,7 @@ export default {
286 286 }).then(function() {
287 287 return exportPost(queryParams);
288 288 }).then(response => {
289   - this.download(response.msg);
  289 + this.downloadExcel(response, '岗位数据.xls');
290 290 })
291 291 }
292 292 }
... ...
src/main/java/cn/iocoder/dashboard/framework/file/config/FileConfiguration.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.file.config;
  2 +
  3 +import org.springframework.boot.context.properties.EnableConfigurationProperties;
  4 +import org.springframework.context.annotation.Configuration;
  5 +
  6 +/**
  7 + * 文件 配置类
  8 + */
  9 +@Configuration
  10 +@EnableConfigurationProperties(FileProperties.class)
  11 +public class FileConfiguration {
  12 +}
... ...
src/main/java/cn/iocoder/dashboard/framework/file/config/FileProperties.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.file.config;
  2 +
  3 +import cn.iocoder.dashboard.modules.system.controller.common.SysFileController;
  4 +import lombok.Data;
  5 +import org.springframework.boot.context.properties.ConfigurationProperties;
  6 +import org.springframework.validation.annotation.Validated;
  7 +
  8 +import javax.validation.constraints.NotNull;
  9 +
  10 +@ConfigurationProperties(prefix = "yudao.file")
  11 +@Validated
  12 +@Data
  13 +public class FileProperties {
  14 +
  15 + /**
  16 + * 对应 {@link SysFileController#}
  17 + */
  18 + @NotNull(message = "基础文件路径不能为空")
  19 + private String basePath;
  20 +
  21 + // TODO 七牛、等等
  22 +
  23 +}
... ...
src/main/java/cn/iocoder/dashboard/framework/file/package-info.java 0 → 100644
  1 +/**
  2 + * 文件的存储,推荐使用七牛、阿里云、华为云、腾讯云等文件服务
  3 + *
  4 + * 在不采用云服务的情况下,我们有几种技术选型:
  5 + * 方案 1. 使用自建的文件服务,例如说 minIO、FastDFS 等等
  6 + * 方案 2. 使用服务器的文件系统存储
  7 + * 方案 3. 使用数据库进行存储
  8 + *
  9 + * 如果考虑额外在搭建服务,推荐方案 1。
  10 + * 对于方案 2 来说,如果要实现文件存储的高可用,需要多台服务器之间做实时同步,可以基于 rsync + inotify 来做
  11 + * 对于方案 3 的话,实现起来最简单,但是数据库本身不适合存储海量的文件
  12 + *
  13 + * 综合考虑,暂时使用方案 3 的方式,比较适合这样一个 all in one 的项目。
  14 + * 随着文件的量级大了之后,还是推荐采用云服务。
  15 + */
  16 +package cn.iocoder.dashboard.framework.file;
... ...
src/main/java/cn/iocoder/dashboard/framework/security/config/SecurityConfiguration.java
1 1 package cn.iocoder.dashboard.framework.security.config;
2 2  
3 3 import cn.iocoder.dashboard.framework.security.core.filter.JwtAuthenticationTokenFilter;
4   -import cn.iocoder.dashboard.framework.security.core.handler.AuthenticationEntryPointImpl;
5 4 import cn.iocoder.dashboard.framework.security.core.handler.LogoutSuccessHandlerImpl;
6 5 import cn.iocoder.dashboard.framework.web.config.WebProperties;
7 6 import org.springframework.boot.context.properties.EnableConfigurationProperties;
... ... @@ -19,8 +18,6 @@ import org.springframework.security.crypto.password.PasswordEncoder;
19 18 import org.springframework.security.web.AuthenticationEntryPoint;
20 19 import org.springframework.security.web.access.AccessDeniedHandler;
21 20 import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
22   -import org.springframework.security.web.authentication.logout.LogoutFilter;
23   -import org.springframework.web.filter.CorsFilter;
24 21  
25 22 import javax.annotation.Resource;
26 23  
... ... @@ -126,12 +123,13 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
126 123 // 登陆的接口,可匿名访问
127 124 .antMatchers(webProperties.getApiPrefix() + "/login").anonymous()
128 125 // 通用的接口,可匿名访问
129   - .antMatchers( webProperties.getApiPrefix() + "/captcha/**").anonymous()
  126 + .antMatchers( webProperties.getApiPrefix() + "/system/captcha/**").anonymous()
130 127 // TODO
131 128 .antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll()
132 129 .antMatchers("/profile/**").anonymous()
133   - .antMatchers("/common/download**").anonymous()
134   - .antMatchers("/common/download/resource**").anonymous()
  130 + // 文件的获取接口,可匿名访问
  131 + .antMatchers(webProperties.getApiPrefix() + "/system/file/get/**").anonymous()
  132 + // TODO
135 133 .antMatchers("/swagger-ui.html").anonymous()
136 134 .antMatchers("/swagger-resources/**").anonymous()
137 135 .antMatchers("/webjars/**").anonymous()
... ...
src/main/java/cn/iocoder/dashboard/modules/system/controller/common/SysCaptchaController.java
... ... @@ -15,7 +15,7 @@ import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
15 15  
16 16 @Api(tags = "验证码 API")
17 17 @RestController
18   -@RequestMapping("/captcha")
  18 +@RequestMapping("/system/captcha")
19 19 public class SysCaptchaController {
20 20  
21 21 @Resource
... ...
src/main/java/cn/iocoder/dashboard/modules/system/controller/common/SysFileController.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.controller.common;
  2 +
  3 +import cn.hutool.core.io.IoUtil;
  4 +import cn.iocoder.dashboard.common.pojo.CommonResult;
  5 +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.common.SysFileDO;
  6 +import cn.iocoder.dashboard.modules.system.service.common.SysFileService;
  7 +import cn.iocoder.dashboard.util.servlet.ServletUtils;
  8 +import io.swagger.annotations.Api;
  9 +import lombok.extern.slf4j.Slf4j;
  10 +import org.springframework.http.HttpStatus;
  11 +import org.springframework.web.bind.annotation.*;
  12 +import org.springframework.web.multipart.MultipartFile;
  13 +
  14 +import javax.annotation.Resource;
  15 +import javax.servlet.http.HttpServletResponse;
  16 +
  17 +import java.io.IOException;
  18 +
  19 +import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
  20 +
  21 +@Api(tags = "文件 API")
  22 +@RestController
  23 +@RequestMapping("/system/file")
  24 +@Slf4j
  25 +public class SysFileController {
  26 +
  27 + @Resource
  28 + private SysFileService fileService;
  29 +
  30 + @PostMapping("/upload")
  31 + public CommonResult<String> uploadFile(@RequestParam("file") MultipartFile file,
  32 + @RequestParam("path") String path) throws IOException {
  33 + return success(fileService.createFile(path, IoUtil.readBytes(file.getInputStream())));
  34 + }
  35 +
  36 + @GetMapping("/get/{path}")
  37 + public void getFile(HttpServletResponse response, @PathVariable("path") String path) throws IOException {
  38 + SysFileDO file = fileService.getFile(path);
  39 + if (file == null) {
  40 + log.warn("[getFile][path({}) 文件不存在]", path);
  41 + response.setStatus(HttpStatus.NOT_FOUND.value());
  42 + return;
  43 + }
  44 + ServletUtils.writeAttachment(response, path, file.getContent());
  45 + }
  46 +
  47 +}
... ...
src/main/java/cn/iocoder/dashboard/modules/system/controller/dept/SysPostController.java
... ... @@ -3,6 +3,7 @@ package cn.iocoder.dashboard.modules.system.controller.dept;
3 3 import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
4 4 import cn.iocoder.dashboard.common.pojo.CommonResult;
5 5 import cn.iocoder.dashboard.common.pojo.PageResult;
  6 +import cn.iocoder.dashboard.framework.excel.core.util.ExcelUtils;
6 7 import cn.iocoder.dashboard.modules.system.controller.dept.vo.post.*;
7 8 import cn.iocoder.dashboard.modules.system.convert.dept.SysPostConvert;
8 9 import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.dept.SysPostDO;
... ... @@ -14,6 +15,8 @@ import org.springframework.validation.annotation.Validated;
14 15 import org.springframework.web.bind.annotation.*;
15 16  
16 17 import javax.annotation.Resource;
  18 +import javax.servlet.http.HttpServletResponse;
  19 +import java.io.IOException;
17 20 import java.util.Collections;
18 21 import java.util.Comparator;
19 22 import java.util.List;
... ... @@ -80,12 +83,16 @@ public class SysPostController {
80 83 return success(SysPostConvert.INSTANCE.convert(postService.getPost(id)));
81 84 }
82 85  
  86 + @GetMapping("/export")
  87 + @ApiOperation("岗位管理")
83 88 // @Log(title = "岗位管理", businessType = BusinessType.EXPORT)
84 89 // @PreAuthorize("@ss.hasPermi('system:post:export')")
85   -// @GetMapping("/export")
86   -// public AjaxResult export(SysPost post) {
87   -// List<SysPost> list = postService.selectPostList(post);
88   -// ExcelUtil<SysPost> util = new ExcelUtil<SysPost>(SysPost.class);
89   -// return util.exportExcel(list, "岗位数据");
90   -// }
  90 + public void export(HttpServletResponse response, @Validated SysPostExportReqVO reqVO) throws IOException {
  91 + List<SysPostDO> posts = postService.listPosts(reqVO);
  92 + List<SysPostExcelVO> excelPosts = SysPostConvert.INSTANCE.convertList03(posts);
  93 + // 输出
  94 + ExcelUtils.write(response, "岗位数据.xls", "岗位列表",
  95 + SysPostExcelVO.class, excelPosts);
  96 + }
  97 +
91 98 }
... ...
src/main/java/cn/iocoder/dashboard/modules/system/controller/dept/vo/post/SysPostExcelRespVO.java renamed to src/main/java/cn/iocoder/dashboard/modules/system/controller/dept/vo/post/SysPostExcelVO.java
1 1 package cn.iocoder.dashboard.modules.system.controller.dept.vo.post;
2 2  
3   -import cn.iocoder.dashboard.framework.excel.Excel;
  3 +import cn.iocoder.dashboard.framework.excel.core.annotations.DictFormat;
  4 +import cn.iocoder.dashboard.framework.excel.core.convert.DictConvert;
  5 +import com.alibaba.excel.annotation.ExcelProperty;
4 6 import lombok.Data;
5 7  
  8 +import static cn.iocoder.dashboard.modules.system.enums.dict.DictTypeEnum.SYS_COMMON_STATUS;
  9 +
6 10 /**
7 11 * 岗位 Excel 导出响应 VO
8 12 */
9 13 @Data
10   -public class SysPostExcelRespVO {
  14 +public class SysPostExcelVO {
11 15  
12   - @Excel(name = "岗位序号", cellType = Excel.ColumnType.NUMERIC)
  16 + @ExcelProperty("岗位序号")
13 17 private Long id;
14 18  
15   - @Excel(name = "岗位编码")
  19 + @ExcelProperty("岗位编码")
16 20 private String code;
17 21  
18   - @Excel(name = "岗位名称")
  22 + @ExcelProperty("岗位名称")
19 23 private String name;
20 24  
21   - @Excel(name = "岗位排序")
  25 + @ExcelProperty("岗位排序")
22 26 private String sort;
23 27  
24   - @Excel(name = "状态", readConverterExp = "0=正常,1=停用")
  28 + @ExcelProperty(value = "状态", converter = DictConvert.class)
  29 + @DictFormat(SYS_COMMON_STATUS)
25 30 private String status;
26 31  
27 32 }
... ...
src/main/java/cn/iocoder/dashboard/modules/system/controller/dept/vo/post/SysPostExportReqVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.controller.dept.vo.post;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +
  7 +@ApiModel(value = "岗位导出 Request VO", description = "参数和 SysPostExcelVO 是一致的")
  8 +@Data
  9 +public class SysPostExportReqVO {
  10 +
  11 + @ApiModelProperty(value = "岗位名称", example = "芋道", notes = "模糊匹配")
  12 + private String name;
  13 +
  14 + @ApiModelProperty(value = "展示状态", example = "1", notes = "参见 SysCommonStatusEnum 枚举类")
  15 + private Integer status;
  16 +
  17 +}
... ...
src/main/java/cn/iocoder/dashboard/modules/system/convert/dept/SysPostConvert.java
1 1 package cn.iocoder.dashboard.modules.system.convert.dept;
2 2  
3 3 import cn.iocoder.dashboard.common.pojo.PageResult;
4   -import cn.iocoder.dashboard.modules.system.controller.dept.vo.post.SysPostCreateReqVO;
5   -import cn.iocoder.dashboard.modules.system.controller.dept.vo.post.SysPostRespVO;
6   -import cn.iocoder.dashboard.modules.system.controller.dept.vo.post.SysPostSimpleRespVO;
7   -import cn.iocoder.dashboard.modules.system.controller.dept.vo.post.SysPostUpdateReqVO;
  4 +import cn.iocoder.dashboard.modules.system.controller.dept.vo.post.*;
8 5 import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.dept.SysPostDO;
9 6 import com.baomidou.mybatisplus.core.metadata.IPage;
10 7 import org.mapstruct.Mapper;
... ... @@ -31,4 +28,6 @@ public interface SysPostConvert {
31 28  
32 29 SysPostDO convert(SysPostUpdateReqVO reqVO);
33 30  
  31 + List<SysPostExcelVO> convertList03(List<SysPostDO> list);
  32 +
34 33 }
... ...
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/common/SysFileMapper.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.dal.mysql.dao.common;
  2 +
  3 +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.common.SysFileDO;
  4 +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  5 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  6 +import org.apache.ibatis.annotations.Mapper;
  7 +
  8 +@Mapper
  9 +public interface SysFileMapper extends BaseMapper<SysFileDO> {
  10 +
  11 + default Integer selectCountById(String id) {
  12 + return selectCount(new QueryWrapper<SysFileDO>().eq("id", id));
  13 + }
  14 +
  15 +}
... ...
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/dept/SysPostMapper.java
... ... @@ -2,6 +2,7 @@ package cn.iocoder.dashboard.modules.system.dal.mysql.dao.dept;
2 2  
3 3 import cn.iocoder.dashboard.framework.mybatis.core.query.QueryWrapperX;
4 4 import cn.iocoder.dashboard.framework.mybatis.core.util.MyBatisUtils;
  5 +import cn.iocoder.dashboard.modules.system.controller.dept.vo.post.SysPostExportReqVO;
5 6 import cn.iocoder.dashboard.modules.system.controller.dept.vo.post.SysPostPageReqVO;
6 7 import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.dept.SysPostDO;
7 8 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
... ... @@ -26,6 +27,11 @@ public interface SysPostMapper extends BaseMapper&lt;SysPostDO&gt; {
26 27 .eqIfPresent("status", reqVO.getStatus()));
27 28 }
28 29  
  30 + default List<SysPostDO> selectList(SysPostExportReqVO reqVO) {
  31 + return selectList(new QueryWrapperX<SysPostDO>().likeIfPresent("name", reqVO.getName())
  32 + .eqIfPresent("status", reqVO.getStatus()));
  33 + }
  34 +
29 35 default SysPostDO selectByName(String name) {
30 36 return selectOne(new QueryWrapper<SysPostDO>().eq("name", name));
31 37 }
... ...
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/common/SysFileDO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.common;
  2 +
  3 +import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO;
  4 +import com.baomidou.mybatisplus.annotation.IdType;
  5 +import com.baomidou.mybatisplus.annotation.TableId;
  6 +import com.baomidou.mybatisplus.annotation.TableName;
  7 +import lombok.Data;
  8 +import lombok.EqualsAndHashCode;
  9 +
  10 +/**
  11 + * 文件表
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@Data
  16 +@TableName("sys_file")
  17 +@EqualsAndHashCode(callSuper = true)
  18 +public class SysFileDO extends BaseDO {
  19 +
  20 + /**
  21 + * 文件路径
  22 + */
  23 + @TableId(type = IdType.INPUT)
  24 + private String id;
  25 + /**
  26 + * 文件内容
  27 + */
  28 + private byte[] content;
  29 +
  30 +}
... ...
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/dept/SysDeptDO.java
... ... @@ -8,7 +8,7 @@ import lombok.Data;
8 8 import lombok.EqualsAndHashCode;
9 9  
10 10 /**
11   - * 部门表 sys_dept
  11 + * 部门表
12 12 *
13 13 * @author ruoyi
14 14 */
... ...
src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java
... ... @@ -69,4 +69,6 @@ public interface SysErrorCodeConstants {
69 69 // ========== 通知公告 1002008000 ==========
70 70 ErrorCode NOTICE_NOT_FOUND = new ErrorCode(1002008001, "当前通知公告不存在");
71 71  
  72 + // ========== 文件 1002009000 ==========
  73 + ErrorCode FILE_PATH_EXISTS = new ErrorCode(1002009001, "文件路径已经存在");
72 74 }
... ...
src/main/java/cn/iocoder/dashboard/modules/system/service/common/SysFileService.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.service.common;
  2 +
  3 +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.common.SysFileDO;
  4 +
  5 +/**
  6 + * 文件 Service 接口
  7 + *
  8 + * @author 芋道源码
  9 + */
  10 +public interface SysFileService {
  11 +
  12 + /**
  13 + * 保存文件,并返回文件的访问路径
  14 + *
  15 + * @param path 文件路径
  16 + * @param content 文件内容
  17 + * @return 文件路径
  18 + */
  19 + String createFile(String path, byte[] content);
  20 +
  21 + /**
  22 + * 获得文件
  23 + *
  24 + * @param path 文件路径
  25 + * @return 文件
  26 + */
  27 + SysFileDO getFile(String path);
  28 +
  29 +}
... ...
src/main/java/cn/iocoder/dashboard/modules/system/service/common/impl/SysFileServiceImpl.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.service.common.impl;
  2 +
  3 +import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil;
  4 +import cn.iocoder.dashboard.framework.file.config.FileProperties;
  5 +import cn.iocoder.dashboard.modules.system.dal.mysql.dao.common.SysFileMapper;
  6 +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.common.SysFileDO;
  7 +import cn.iocoder.dashboard.modules.system.service.common.SysFileService;
  8 +import org.springframework.stereotype.Service;
  9 +
  10 +import javax.annotation.Resource;
  11 +
  12 +import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.FILE_PATH_EXISTS;
  13 +
  14 +/**
  15 + * 文件 Service 实现类
  16 + *
  17 + * @author 芋道源码
  18 + */
  19 +@Service
  20 +public class SysFileServiceImpl implements SysFileService {
  21 +
  22 + @Resource
  23 + private SysFileMapper fileMapper;
  24 +
  25 + @Resource
  26 + private FileProperties fileProperties;
  27 +
  28 + @Override
  29 + public String createFile(String path, byte[] content) {
  30 + if (fileMapper.selectCountById(path) > 0) {
  31 + throw ServiceExceptionUtil.exception(FILE_PATH_EXISTS);
  32 + }
  33 + // 保存到数据库
  34 + SysFileDO file = new SysFileDO();
  35 + file.setId(path);
  36 + file.setContent(content);
  37 + fileMapper.insert(file);
  38 + // 拼接路径返回
  39 + return fileProperties.getBasePath() + path;
  40 + }
  41 +
  42 + @Override
  43 + public SysFileDO getFile(String path) {
  44 + return fileMapper.selectById(path);
  45 + }
  46 +
  47 +}
... ...
src/main/java/cn/iocoder/dashboard/modules/system/service/dept/SysPostService.java
... ... @@ -2,6 +2,7 @@ package cn.iocoder.dashboard.modules.system.service.dept;
2 2  
3 3 import cn.iocoder.dashboard.common.pojo.PageResult;
4 4 import cn.iocoder.dashboard.modules.system.controller.dept.vo.post.SysPostCreateReqVO;
  5 +import cn.iocoder.dashboard.modules.system.controller.dept.vo.post.SysPostExportReqVO;
5 6 import cn.iocoder.dashboard.modules.system.controller.dept.vo.post.SysPostPageReqVO;
6 7 import cn.iocoder.dashboard.modules.system.controller.dept.vo.post.SysPostUpdateReqVO;
7 8 import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.dept.SysPostDO;
... ... @@ -18,7 +19,7 @@ import java.util.List;
18 19 public interface SysPostService {
19 20  
20 21 /**
21   - * 获得所有岗位列表
  22 + * 获得符合条件的岗位列表
22 23 *
23 24 * @param ids 岗位编号数组。如果为空,不进行筛选
24 25 * @param statuses 状态数组。如果为空,不进行筛选
... ... @@ -35,6 +36,14 @@ public interface SysPostService {
35 36 PageResult<SysPostDO> pagePosts(SysPostPageReqVO reqVO);
36 37  
37 38 /**
  39 + * 获得岗位列表
  40 + *
  41 + * @param reqVO 查询条件
  42 + * @return 部门列表
  43 + */
  44 + List<SysPostDO> listPosts(SysPostExportReqVO reqVO);
  45 +
  46 + /**
38 47 * 获得岗位信息
39 48 *
40 49 * @param id 岗位编号
... ...
src/main/java/cn/iocoder/dashboard/modules/system/service/dept/impl/SysPostServiceImpl.java
... ... @@ -3,6 +3,7 @@ package cn.iocoder.dashboard.modules.system.service.dept.impl;
3 3 import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil;
4 4 import cn.iocoder.dashboard.common.pojo.PageResult;
5 5 import cn.iocoder.dashboard.modules.system.controller.dept.vo.post.SysPostCreateReqVO;
  6 +import cn.iocoder.dashboard.modules.system.controller.dept.vo.post.SysPostExportReqVO;
6 7 import cn.iocoder.dashboard.modules.system.controller.dept.vo.post.SysPostPageReqVO;
7 8 import cn.iocoder.dashboard.modules.system.controller.dept.vo.post.SysPostUpdateReqVO;
8 9 import cn.iocoder.dashboard.modules.system.convert.dept.SysPostConvert;
... ... @@ -39,6 +40,11 @@ public class SysPostServiceImpl implements SysPostService {
39 40 }
40 41  
41 42 @Override
  43 + public List<SysPostDO> listPosts(SysPostExportReqVO reqVO) {
  44 + return postMapper.selectList(reqVO);
  45 + }
  46 +
  47 + @Override
42 48 public SysPostDO getPost(Long id) {
43 49 return postMapper.selectById(id);
44 50 }
... ...
src/main/java/cn/iocoder/dashboard/util/servlet/ServletUtils.java
1 1 package cn.iocoder.dashboard.util.servlet;
2 2  
  3 +import cn.hutool.core.io.IoUtil;
3 4 import cn.hutool.extra.servlet.ServletUtil;
4 5 import com.alibaba.fastjson.JSON;
5 6 import org.springframework.http.MediaType;
6 7  
7   -
8 8 import javax.servlet.http.HttpServletResponse;
  9 +import java.io.IOException;
  10 +import java.net.URLEncoder;
9 11  
10 12 /**
11 13 * 客户端工具类
... ... @@ -14,10 +16,32 @@ import javax.servlet.http.HttpServletResponse;
14 16 */
15 17 public class ServletUtils {
16 18  
  19 + /**
  20 + * 返回 JSON 字符串
  21 + *
  22 + * @param response 响应
  23 + * @param object 对象,会序列化成 JSON 字符串
  24 + */
17 25 @SuppressWarnings("deprecation") // 必须使用 APPLICATION_JSON_UTF8_VALUE,否则会乱码
18 26 public static void writeJSON(HttpServletResponse response, Object object) {
19 27 String content = JSON.toJSONString(object);
20 28 ServletUtil.write(response, content, MediaType.APPLICATION_JSON_UTF8_VALUE);
21 29 }
22 30  
  31 + /**
  32 + * 返回附件
  33 + *
  34 + * @param response 响应
  35 + * @param filename 文件名
  36 + * @param content 附件内容
  37 + * @throws IOException
  38 + */
  39 + public static void writeAttachment(HttpServletResponse response, String filename, byte[] content) throws IOException {
  40 + // 设置 header 和 contentType
  41 + response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
  42 + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
  43 + // 输出附件
  44 + IoUtil.write(response.getOutputStream(), false, content);
  45 + }
  46 +
23 47 }
... ...
src/main/resources/application.yaml
... ... @@ -17,6 +17,12 @@ spring:
17 17 database: 0
18 18 # 连接超时时间
19 19 timeout: 10s
  20 + # Servlet 配置
  21 + servlet:
  22 + # 文件上传相关配置项
  23 + multipart:
  24 + max-file-size: 16MB # 单个文件大小
  25 + max-request-size: 32MB # 设置总上传的文件大小
20 26  
21 27 # 芋道配置项,设置当前项目所有自定义的配置
22 28 yudao:
... ... @@ -38,6 +44,8 @@ yudao:
38 44 timeout: 5m
39 45 width: 160
40 46 height: 60
  47 + file:
  48 + base-path: http://127.0.0.1:1024/api/file/get/
41 49  
42 50 # MyBatis Plus 的配置项
43 51 mybatis-plus:
... ...