Commit 629fa9b40732d807cb12fdc7f5279460cd17d55a
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
ruoyi-ui/src/api/system/post.js
ruoyi-ui/src/views/system/post/index.vue
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
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<SysPostDO> { |
| 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
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: | ... | ... |