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