From aca60186e0f525fd01e363077f2d2765b37df835 Mon Sep 17 00:00:00 2001 From: dhy1725534722 <1725534722@qq.com> Date: Tue, 26 Mar 2024 16:50:02 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 17 +- ruoyi-admin/pom.xml | 29 +- .../main/java/com/ruoyi/RuoYiApplication.java | 33 +- .../ent/controller/JMemorandumController.java | 98 ++ .../ent/controller/JProjectController.java | 127 ++ .../com/ruoyi/jjh/ent/entity/JMemorandum.java | 72 + .../com/ruoyi/jjh/ent/entity/JProject.java | 76 + .../entity/request/JMemorandumRequest.java | 39 + .../jjh/ent/mapper/JMemorandumMapper.java | 26 + .../ruoyi/jjh/ent/mapper/JProjectMapper.java | 25 + .../jjh/ent/service/JMemorandumService.java | 25 + .../jjh/ent/service/JProjectService.java | 26 + .../service/impl/JMemorandumServiceImpl.java | 33 + .../ent/service/impl/JProjectServiceImpl.java | 34 + .../web/controller/tool/TestController.java | 183 --- .../ruoyi/web/core/config/SwaggerConfig.java | 47 +- .../src/main/resources/application.yml | 14 +- .../mapper/jjh/JMemorandumMapper.xml | 21 + .../resources/mapper/jjh/JProjectMapper.xml | 27 + ruoyi-common/pom.xml | 6 + .../common/utils/poi/ProjectExcelUtil.java | 1453 +++++++++++++++++ .../ruoyi/framework/config/MyBatisConfig.java | 43 +- .../framework/config/SecurityConfig.java | 3 + 23 files changed, 2179 insertions(+), 278 deletions(-) create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/controller/JMemorandumController.java create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/controller/JProjectController.java create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/entity/JMemorandum.java create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/entity/JProject.java create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/entity/request/JMemorandumRequest.java create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/mapper/JMemorandumMapper.java create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/mapper/JProjectMapper.java create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/service/JMemorandumService.java create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/service/JProjectService.java create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/service/impl/JMemorandumServiceImpl.java create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/service/impl/JProjectServiceImpl.java delete mode 100644 ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/TestController.java create mode 100644 ruoyi-admin/src/main/resources/mapper/jjh/JMemorandumMapper.xml create mode 100644 ruoyi-admin/src/main/resources/mapper/jjh/JProjectMapper.xml create mode 100644 ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ProjectExcelUtil.java diff --git a/pom.xml b/pom.xml index 35be802..8784b15 100644 --- a/pom.xml +++ b/pom.xml @@ -34,6 +34,11 @@ + + com.github.xiaoymin + knife4j-spring-boot-starter + 3.0.3 + @@ -72,18 +77,6 @@ ${oshi.version} - - - io.springfox - springfox-boot-starter - ${swagger.version} - - - io.swagger - swagger-models - - - diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml index b97ef88..a1e5ce4 100644 --- a/ruoyi-admin/pom.xml +++ b/ruoyi-admin/pom.xml @@ -16,27 +16,22 @@ - - - org.springframework.boot - spring-boot-devtools - true + cn.hutool + hutool-all + 5.8.23 - - - io.springfox - springfox-boot-starter + com.github.xiaoymin + knife4j-spring-boot-starter + 3.0.3 - - + - io.swagger - swagger-models - 1.6.2 + org.springframework.boot + spring-boot-devtools + true - mysql @@ -60,6 +55,10 @@ com.ruoyi ruoyi-generator + + org.projectlombok + lombok + diff --git a/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java b/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java index 32eb6f1..cdb2601 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java @@ -3,6 +3,11 @@ package com.ruoyi; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.env.Environment; + +import java.net.InetAddress; +import java.net.UnknownHostException; /** * 启动程序 @@ -14,17 +19,21 @@ public class RuoYiApplication { public static void main(String[] args) { - // System.setProperty("spring.devtools.restart.enabled", "false"); - SpringApplication.run(RuoYiApplication.class, args); - System.out.println("(♥◠‿◠)ノ゙ 若依启动成功 ლ(´ڡ`ლ)゙ \n" + - " .-------. ____ __ \n" + - " | _ _ \\ \\ \\ / / \n" + - " | ( ' ) | \\ _. / ' \n" + - " |(_ o _) / _( )_ .' \n" + - " | (_,_).' __ ___(_ o _)' \n" + - " | |\\ \\ | || |(_,_)' \n" + - " | | \\ `' /| `-' / \n" + - " | | \\ / \\ / \n" + - " ''-' `'-' `-..-' "); + ConfigurableApplicationContext application = SpringApplication.run(RuoYiApplication.class, args); + Environment env = application.getEnvironment(); + String ip = null; + try { + ip = InetAddress.getLocalHost().getHostAddress(); + } catch (UnknownHostException e) { + throw new RuntimeException(e); + } + String port = env.getProperty("server.port"); + String path = env.getProperty("server.servlet.context-path"); + path = path.isEmpty() ? "" : path; + System.out.println("\n----------------------------------------------------------\n\t" + + "Application is running! Access URLs:\n\t" + + "swagger-ui: http://localhost:" + port + path + "doc.html\n\t" + + "swagger-ui: http://" + ip + ":" + port + path + "doc.html\n\t" + + "----------------------------------------------------------"); } } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/controller/JMemorandumController.java b/ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/controller/JMemorandumController.java new file mode 100644 index 0000000..aa51c09 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/controller/JMemorandumController.java @@ -0,0 +1,98 @@ +package com.ruoyi.jjh.ent.controller; + + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.jjh.ent.entity.JMemorandum; +import com.ruoyi.jjh.ent.entity.request.JMemorandumRequest; +import com.ruoyi.jjh.ent.service.JMemorandumService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * 备忘录(JMemorandum)表控制层 + * + * @author makejava + * @since 2024-03-26 10:34:03 + */ +@RestController +@RequestMapping("/jjh/jMemorandum") +@Api(tags = "备忘录表") +public class JMemorandumController extends BaseController { + /** + * 服务对象 + */ + @Resource + private JMemorandumService jMemorandumService; + + /** + * 分页查询所有数据 + * + * @param page 分页对象 + * @param jMemorandumRequest 查询实体 + * @return 所有数据 + */ + @ApiOperation(value = "分页查询所有数据", response = JMemorandum.class) + @GetMapping + public AjaxResult selectAll(Page page, JMemorandumRequest jMemorandumRequest) { + return success(jMemorandumService.page(page,jMemorandumRequest)); + } + + /** + * 通过主键查询单条数据 + * + * @param id 主键 + * @return 单条数据 + */ + @ApiOperation(value = "通过主键查询单条数据", response = JMemorandum.class) + @GetMapping("{id}") + public AjaxResult selectOne(@PathVariable Serializable id) { + return success(this.jMemorandumService.getById(id)); + } + + /** + * 新增数据 + * + * @param jMemorandum 实体对象 + * @return 新增结果 + */ + @ApiOperation(value = "新增数据") + @PostMapping + public AjaxResult insert(@RequestBody JMemorandum jMemorandum) { + jMemorandum.setCreateTime(new Date()); + return success(this.jMemorandumService.save(jMemorandum)); + } + + /** + * 修改数据 + * + * @param jMemorandum 实体对象 + * @return 修改结果 + */ + @ApiOperation(value = "修改数据") + @PutMapping + public AjaxResult update(@RequestBody JMemorandum jMemorandum) { + jMemorandum.setUpdateTime(new Date()); + return success(this.jMemorandumService.updateById(jMemorandum)); + } + + /** + * 删除数据 + * + * @param idList 主键结合 + * @return 删除结果 + */ + @ApiOperation(value = "删除数据") + @DeleteMapping + public AjaxResult delete(@RequestParam("idList") List idList) { + return success(this.jMemorandumService.removeByIds(idList)); + } +} + diff --git a/ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/controller/JProjectController.java b/ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/controller/JProjectController.java new file mode 100644 index 0000000..a991ec4 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/controller/JProjectController.java @@ -0,0 +1,127 @@ +package com.ruoyi.jjh.ent.controller; + + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.common.utils.ServletUtils; +import com.ruoyi.common.utils.poi.ProjectExcelUtil; +import com.ruoyi.jjh.ent.entity.JProject; +import com.ruoyi.jjh.ent.service.JProjectService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.io.Serializable; +import java.util.List; + +/** + * 项目表(JProject)表控制层 + * + * @author makejava + * @since 2024-03-25 11:49:34 + */ +@RestController +@RequestMapping("/jjh/jProject") +@Api(tags = "项目表") +public class JProjectController extends BaseController { + /** + * 服务对象 + */ + @Resource + private JProjectService jProjectService; + + /** + * 分页查询项目 + * + * @param page 分页对象 + * @param jProject 查询实体 + * @return 所有数据 + */ + @ApiOperation(value = "分页查询项目", response = JProject.class) + @GetMapping + public AjaxResult selectAll(Page page, JProject jProject) { + return success(jProjectService.page(page,jProject)); + } + + /** + * 通过主键查询单条数据 + * + * @param id 主键 + * @return 单条数据 + */ + @ApiOperation(value = "通过主键查询单条项目", response = JProject.class) + @GetMapping("{id}") + public AjaxResult selectOne(@PathVariable Serializable id) { + return success(this.jProjectService.getById(id)); + } + + /** + * 新增数据 + * + * @param jProject 实体对象 + * @return 新增结果 + */ + @ApiOperation(value = "新增项目") + @PostMapping + public AjaxResult insert(@RequestBody JProject jProject) { + return success(this.jProjectService.save(jProject)); + } + + /** + * 修改数据 + * + * @param jProject 实体对象 + * @return 修改结果 + */ + @ApiOperation(value = "修改项目") + @PutMapping + public AjaxResult update(@RequestBody JProject jProject) { + return success(this.jProjectService.updateById(jProject)); + } + + /** + * 删除数据 + * + * @param idList 主键结合 + * @return 删除结果 + */ + @ApiOperation(value = "删除项目") + @DeleteMapping + public AjaxResult delete(@RequestParam("idList") List idList) { + return success(this.jProjectService.removeByIds(idList)); + } + + /** + * 导入excel项目数据 + * + */ + @ApiOperation(value = "导入excel项目数据") + @PostMapping(value = "/export",consumes ="multipart/form-data") + public AjaxResult importProject(@RequestPart("file") MultipartFile file) throws Exception { + HttpServletRequest req = ServletUtils.getRequest(); +// String token = req.getHeader("Authentication"); +// if (StrUtil.isEmpty(token)) { +// throw new BaseException("用户未登录"); +// } + ProjectExcelUtil util = new ProjectExcelUtil<>(JProject.class); + List proList = util.importExcel(file.getInputStream()); + StringBuilder successMsg = new StringBuilder(); + if(proList == null && proList.isEmpty()){ + throw new ServiceException("项目导入数据不能为空"); + }else { + if (!proList.isEmpty()) { + jProjectService.saveBatch(proList); + successMsg.append("导入成功"); + } else { + successMsg.append("导入失败,文件为空"); + } + } + return AjaxResult.success(successMsg); + } +} + diff --git a/ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/entity/JMemorandum.java b/ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/entity/JMemorandum.java new file mode 100644 index 0000000..f53750d --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/entity/JMemorandum.java @@ -0,0 +1,72 @@ +package com.ruoyi.jjh.ent.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +/** + * 备忘录(JMemorandum)表实体类 + * + * @author makejava + * @since 2024-03-26 10:34:03 + */ +@ApiModel("备忘录表") +@TableName(value = "j_memorandum") +@Data +public class JMemorandum { + /** + * Id + */ + @TableId(value = "id", type = IdType.AUTO) + @ApiModelProperty("Id") + private Long id; + /** + * 项目表关联id + */ + @ApiModelProperty("项目表关联id") + private Long projectId; + /** + * 名字 + */ + @ApiModelProperty("名字") + private String name; + + /** + * 主题/关键字 + */ + @ApiModelProperty("主题/关键字") + private String keywords; + /** + * 备忘内容 + */ + @ApiModelProperty("备忘内容") + + private String content; + + private Long createId; + + private String createBy; + + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @ApiModelProperty("创建时间") + private Date createTime; + + private Long updateId; + + private String updateBy; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @ApiModelProperty("更新时间") + private Date updateTime; +} + diff --git a/ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/entity/JProject.java b/ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/entity/JProject.java new file mode 100644 index 0000000..05c1d4d --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/entity/JProject.java @@ -0,0 +1,76 @@ +package com.ruoyi.jjh.ent.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.ruoyi.common.annotation.Excel; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import io.swagger.models.auth.In; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +/** + * 项目表(JProject)表实体类 + * + * @author makejava + * @since 2024-03-25 11:49:34 + */ +@ApiModel("项目表") +@TableName(value = "j_project") +@Data +public class JProject{ + /** + * Id + */ + @TableId(value = "id", type = IdType.AUTO) + @ApiModelProperty("Id") + private Long id; + + /** + * 项目名称 + */ + @Excel(name = "项目名称") + @ApiModelProperty("项目名称") + private String projectName; + + + /** + * 项目分类 + */ +// @Excel(name = "项目分类", readConverterExp = "0=省现代服务业重点项目,1=两业融合试点单位") + @Excel(name = "项目分类") + @ApiModelProperty("项目分类") + private String projectClassify; + + /** + * 申报单位 + */ + @Excel(name = "申报单位") + @ApiModelProperty("申报单位") + private String declareUnit; + + /** + * 年份 + */ + @Excel(name = "年份") + private String projectYear; + + /** + * 其余字段和数据 + */ + @Excel(name = "其余字段和数据") + @ApiModelProperty("其余字段和数据") + private String otherJson; + + /** + * 状态 + */ + @ApiModelProperty("状态") + private Integer status; +} + diff --git a/ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/entity/request/JMemorandumRequest.java b/ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/entity/request/JMemorandumRequest.java new file mode 100644 index 0000000..1fbd77e --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/entity/request/JMemorandumRequest.java @@ -0,0 +1,39 @@ +package com.ruoyi.jjh.ent.entity.request; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +/** + * @author du + * @since 2024/3/26 10:48 + */ +@Data +@ApiModel("备忘录请求类") +public class JMemorandumRequest { + /** + * 名字 + */ + @ApiModelProperty("名字") + private String name; + + /** + * 开始时间 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @ApiModelProperty("开始时间") + private Date startTime; + + /** + * 结束时间 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @ApiModelProperty("结束时间") + private Date endTime; +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/mapper/JMemorandumMapper.java b/ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/mapper/JMemorandumMapper.java new file mode 100644 index 0000000..5e0f879 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/mapper/JMemorandumMapper.java @@ -0,0 +1,26 @@ +package com.ruoyi.jjh.ent.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.ruoyi.jjh.ent.entity.JMemorandum; +import com.ruoyi.jjh.ent.entity.request.JMemorandumRequest; +import org.apache.ibatis.annotations.Param; + +/** + * 备忘录(JMemorandum)表数据库访问层 + * + * @author makejava + * @since 2024-03-26 10:34:03 + */ +public interface JMemorandumMapper extends BaseMapper { + + /** + * 分页查询所有数据 + * + * @param page 分页对象 + * @param jMemorandumRequest 查询实体 + * @return 所有数据 + */ + Page page(Page page, @Param("req") JMemorandumRequest jMemorandumRequest); +} + diff --git a/ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/mapper/JProjectMapper.java b/ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/mapper/JProjectMapper.java new file mode 100644 index 0000000..3d44211 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/mapper/JProjectMapper.java @@ -0,0 +1,25 @@ +package com.ruoyi.jjh.ent.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.ruoyi.jjh.ent.entity.JProject; +import org.apache.ibatis.annotations.Param; + +/** + * 项目表(JProject)表数据库访问层 + * + * @author makejava + * @since 2024-03-25 11:49:34 + */ +public interface JProjectMapper extends BaseMapper { + + /** + * 分页查询所有数据 + * + * @param page 分页对象 + * @param jProject 查询实体 + * @return 所有数据 + */ + Page page(Page page,@Param("req") JProject jProject); +} + diff --git a/ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/service/JMemorandumService.java b/ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/service/JMemorandumService.java new file mode 100644 index 0000000..50429f4 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/service/JMemorandumService.java @@ -0,0 +1,25 @@ +package com.ruoyi.jjh.ent.service; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import com.ruoyi.jjh.ent.entity.JMemorandum; +import com.ruoyi.jjh.ent.entity.request.JMemorandumRequest; + +/** + * 备忘录(JMemorandum)表服务接口 + * + * @author makejava + * @since 2024-03-26 10:34:03 + */ +public interface JMemorandumService extends IService { + + /** + * 分页查询所有数据 + * + * @param page 分页对象 + * @param jMemorandumRequest 查询实体 + * @return 所有数据 + */ + Page page(Page page, JMemorandumRequest jMemorandumRequest); +} + diff --git a/ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/service/JProjectService.java b/ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/service/JProjectService.java new file mode 100644 index 0000000..a5a1cfd --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/service/JProjectService.java @@ -0,0 +1,26 @@ +package com.ruoyi.jjh.ent.service; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import com.ruoyi.jjh.ent.entity.JProject; + + +/** + * 项目表(JProject)表服务接口 + * + * @author makejava + * @since 2024-03-25 11:49:34 + */ +public interface JProjectService extends IService { + + /** + * 分页查询所有数据 + * + * @param page 分页对象 + * @param jProject 查询实体 + * @return 所有数据 + */ + Page page(Page page, JProject jProject); + +} + diff --git a/ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/service/impl/JMemorandumServiceImpl.java b/ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/service/impl/JMemorandumServiceImpl.java new file mode 100644 index 0000000..6477d2e --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/service/impl/JMemorandumServiceImpl.java @@ -0,0 +1,33 @@ +package com.ruoyi.jjh.ent.service.impl; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.ruoyi.jjh.ent.entity.request.JMemorandumRequest; +import com.ruoyi.jjh.ent.mapper.JMemorandumMapper; +import com.ruoyi.jjh.ent.entity.JMemorandum; +import com.ruoyi.jjh.ent.service.JMemorandumService; +import org.springframework.stereotype.Service; + +/** + * 备忘录(JMemorandum)表服务实现类 + * + * @author makejava + * @since 2024-03-26 10:34:03 + */ +@Service("jMemorandumService") +public class JMemorandumServiceImpl extends ServiceImpl implements JMemorandumService { + + /** + * 分页查询所有数据 + * + * @param page 分页对象 + * @param jMemorandumRequest 查询实体 + * @return 所有数据 + */ + @Override + public Page page(Page page, JMemorandumRequest jMemorandumRequest) { + return baseMapper.page(page,jMemorandumRequest); + } + +} + diff --git a/ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/service/impl/JProjectServiceImpl.java b/ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/service/impl/JProjectServiceImpl.java new file mode 100644 index 0000000..c6dff81 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/jjh/ent/service/impl/JProjectServiceImpl.java @@ -0,0 +1,34 @@ +package com.ruoyi.jjh.ent.service.impl; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.ruoyi.jjh.ent.mapper.JProjectMapper; +import com.ruoyi.jjh.ent.entity.JProject; +import com.ruoyi.jjh.ent.service.JProjectService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 项目表(JProject)表服务实现类 + * + * @author makejava + * @since 2024-03-25 11:49:34 + */ +@Service("jProjectService") +public class JProjectServiceImpl extends ServiceImpl implements JProjectService { + + /** + * 分页查询所有数据 + * + * @param page 分页对象 + * @param jProject 查询实体 + * @return 所有数据 + */ + @Override + public Page page(Page page, JProject jProject) { + return baseMapper.page(page,jProject); + } + +} + diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/TestController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/TestController.java deleted file mode 100644 index b4f6bac..0000000 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/TestController.java +++ /dev/null @@ -1,183 +0,0 @@ -package com.ruoyi.web.controller.tool; - -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import com.ruoyi.common.core.controller.BaseController; -import com.ruoyi.common.core.domain.R; -import com.ruoyi.common.utils.StringUtils; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import io.swagger.annotations.ApiOperation; - -/** - * swagger 用户测试方法 - * - * @author ruoyi - */ -@Api("用户信息管理") -@RestController -@RequestMapping("/test/user") -public class TestController extends BaseController -{ - private final static Map users = new LinkedHashMap(); - { - users.put(1, new UserEntity(1, "admin", "admin123", "15888888888")); - users.put(2, new UserEntity(2, "ry", "admin123", "15666666666")); - } - - @ApiOperation("获取用户列表") - @GetMapping("/list") - public R> userList() - { - List userList = new ArrayList(users.values()); - return R.ok(userList); - } - - @ApiOperation("获取用户详细") - @ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class) - @GetMapping("/{userId}") - public R getUser(@PathVariable Integer userId) - { - if (!users.isEmpty() && users.containsKey(userId)) - { - return R.ok(users.get(userId)); - } - else - { - return R.fail("用户不存在"); - } - } - - @ApiOperation("新增用户") - @ApiImplicitParams({ - @ApiImplicitParam(name = "userId", value = "用户id", dataType = "Integer", dataTypeClass = Integer.class), - @ApiImplicitParam(name = "username", value = "用户名称", dataType = "String", dataTypeClass = String.class), - @ApiImplicitParam(name = "password", value = "用户密码", dataType = "String", dataTypeClass = String.class), - @ApiImplicitParam(name = "mobile", value = "用户手机", dataType = "String", dataTypeClass = String.class) - }) - @PostMapping("/save") - public R save(UserEntity user) - { - if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId())) - { - return R.fail("用户ID不能为空"); - } - users.put(user.getUserId(), user); - return R.ok(); - } - - @ApiOperation("更新用户") - @PutMapping("/update") - public R update(@RequestBody UserEntity user) - { - if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId())) - { - return R.fail("用户ID不能为空"); - } - if (users.isEmpty() || !users.containsKey(user.getUserId())) - { - return R.fail("用户不存在"); - } - users.remove(user.getUserId()); - users.put(user.getUserId(), user); - return R.ok(); - } - - @ApiOperation("删除用户信息") - @ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class) - @DeleteMapping("/{userId}") - public R delete(@PathVariable Integer userId) - { - if (!users.isEmpty() && users.containsKey(userId)) - { - users.remove(userId); - return R.ok(); - } - else - { - return R.fail("用户不存在"); - } - } -} - -@ApiModel(value = "UserEntity", description = "用户实体") -class UserEntity -{ - @ApiModelProperty("用户ID") - private Integer userId; - - @ApiModelProperty("用户名称") - private String username; - - @ApiModelProperty("用户密码") - private String password; - - @ApiModelProperty("用户手机") - private String mobile; - - public UserEntity() - { - - } - - public UserEntity(Integer userId, String username, String password, String mobile) - { - this.userId = userId; - this.username = username; - this.password = password; - this.mobile = mobile; - } - - public Integer getUserId() - { - return userId; - } - - public void setUserId(Integer userId) - { - this.userId = userId; - } - - public String getUsername() - { - return username; - } - - public void setUsername(String username) - { - this.username = username; - } - - public String getPassword() - { - return password; - } - - public void setPassword(String password) - { - this.password = password; - } - - public String getMobile() - { - return mobile; - } - - public void setMobile(String mobile) - { - this.mobile = mobile; - } -} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/core/config/SwaggerConfig.java b/ruoyi-admin/src/main/java/com/ruoyi/web/core/config/SwaggerConfig.java index ae1c3ec..695ac29 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/core/config/SwaggerConfig.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/core/config/SwaggerConfig.java @@ -2,6 +2,9 @@ package com.ruoyi.web.core.config; import java.util.ArrayList; import java.util.List; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; @@ -24,30 +27,34 @@ import springfox.documentation.spring.web.plugins.Docket; /** * Swagger2的接口配置 - * + * * @author ruoyi */ @Configuration -public class SwaggerConfig -{ - /** 系统基础配置 */ +public class SwaggerConfig { + /** + * 系统基础配置 + */ @Autowired private RuoYiConfig ruoyiConfig; - /** 是否开启swagger */ - @Value("${swagger.enabled}") + /** + * 是否开启swagger + */ + @Value("${knife4j.enable}") private boolean enabled; - /** 设置请求的统一前缀 */ - @Value("${swagger.pathMapping}") + /** + * 设置请求的统一前缀 + */ + @Value("${server.servlet.context-path}") private String pathMapping; /** * 创建API */ @Bean - public Docket createRestApi() - { + public Docket createRestApi() { return new Docket(DocumentationType.OAS_30) // 是否启用Swagger .enable(enabled) @@ -65,24 +72,24 @@ public class SwaggerConfig /* 设置安全模式,swagger可以设置访问token */ .securitySchemes(securitySchemes()) .securityContexts(securityContexts()) - .pathMapping(pathMapping); + .pathMapping(pathMapping) + // 排除mybatis-plus的分页参数 + .ignoredParameterTypes(Page.class, IPage.class); } /** * 安全模式,这里指定token通过Authorization头请求头传递 */ - private List securitySchemes() - { + private List securitySchemes() { List apiKeyList = new ArrayList(); - apiKeyList.add(new ApiKey("Authorization", "Authorization", In.HEADER.toValue())); +// apiKeyList.add(new ApiKey("Authorization", "Authorization", In.HEADER.toValue())); return apiKeyList; } /** * 安全上下文 */ - private List securityContexts() - { + private List securityContexts() { List securityContexts = new ArrayList<>(); securityContexts.add( SecurityContext.builder() @@ -95,8 +102,7 @@ public class SwaggerConfig /** * 默认的安全上引用 */ - private List defaultAuth() - { + private List defaultAuth() { AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything"); AuthorizationScope[] authorizationScopes = new AuthorizationScope[1]; authorizationScopes[0] = authorizationScope; @@ -108,12 +114,11 @@ public class SwaggerConfig /** * 添加摘要信息 */ - private ApiInfo apiInfo() - { + private ApiInfo apiInfo() { // 用ApiInfoBuilder进行定制 return new ApiInfoBuilder() // 设置标题 - .title("标题:若依管理系统_接口文档") + .title("金鸡湖品牌管理") // 描述 .description("描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...") // 作者信息 diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index 93ee49c..b7cb28d 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -97,8 +97,8 @@ token: # 令牌有效期(默认30分钟) expireTime: 30 -# MyBatis配置 -mybatis: +# mybatis-plus配置 +mybatis-plus: # 搜索指定包别名 typeAliasesPackage: com.ruoyi.**.domain # 配置mapper的扫描,找到所有的mapper.xml映射文件 @@ -112,12 +112,10 @@ pagehelper: supportMethodsArguments: true params: count=countSql -# Swagger配置 -swagger: - # 是否开启swagger - enabled: true - # 请求前缀 - pathMapping: /dev-api +# 文档配置 +knife4j: + # 开启增强配置 + enable: true # 防止XSS攻击 xss: diff --git a/ruoyi-admin/src/main/resources/mapper/jjh/JMemorandumMapper.xml b/ruoyi-admin/src/main/resources/mapper/jjh/JMemorandumMapper.xml new file mode 100644 index 0000000..b1fb097 --- /dev/null +++ b/ruoyi-admin/src/main/resources/mapper/jjh/JMemorandumMapper.xml @@ -0,0 +1,21 @@ + + + + + + diff --git a/ruoyi-admin/src/main/resources/mapper/jjh/JProjectMapper.xml b/ruoyi-admin/src/main/resources/mapper/jjh/JProjectMapper.xml new file mode 100644 index 0000000..2275f22 --- /dev/null +++ b/ruoyi-admin/src/main/resources/mapper/jjh/JProjectMapper.xml @@ -0,0 +1,27 @@ + + + + + + diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml index c595a10..1c939ed 100644 --- a/ruoyi-common/pom.xml +++ b/ruoyi-common/pom.xml @@ -17,6 +17,12 @@ + + com.baomidou + mybatis-plus-boot-starter + 3.5.3.1 + + org.springframework diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ProjectExcelUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ProjectExcelUtil.java new file mode 100644 index 0000000..05ebd10 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ProjectExcelUtil.java @@ -0,0 +1,1453 @@ +package com.ruoyi.common.utils.poi; + +import com.ruoyi.common.annotation.Excel; +import com.ruoyi.common.annotation.Excel.ColumnType; +import com.ruoyi.common.annotation.Excel.Type; +import com.ruoyi.common.annotation.Excels; +import com.ruoyi.common.config.RuoYiConfig; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.text.Convert; +import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.common.exception.UtilException; +import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.common.utils.DictUtils; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.utils.file.FileTypeUtils; +import com.ruoyi.common.utils.file.FileUtils; +import com.ruoyi.common.utils.file.ImageUtils; +import com.ruoyi.common.utils.reflect.ReflectUtils; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.RegExUtils; +import org.apache.commons.lang3.reflect.FieldUtils; +import org.apache.poi.hssf.usermodel.*; +import org.apache.poi.ooxml.POIXMLDocumentPart; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.ss.util.CellRangeAddressList; +import org.apache.poi.util.IOUtils; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; +import org.apache.poi.xssf.usermodel.*; +import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.math.BigDecimal; +import java.text.DecimalFormat; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; + +/** + * Excel相关处理 + * + * @author ruoyi + */ +public class ProjectExcelUtil { + private static final Logger log = LoggerFactory.getLogger(ProjectExcelUtil.class); + + public static final String FORMULA_REGEX_STR = "=|-|\\+|@"; + + public static final String[] FORMULA_STR = {"=", "-", "+", "@"}; + + /** + * 用于dictType属性数据存储,避免重复查缓存 + */ + public Map sysDictMap = new HashMap(); + + /** + * Excel sheet最大行数,默认65536 + */ + public static final int sheetSize = 65536; + + /** + * 工作表名称 + */ + private String sheetName; + + /** + * 导出类型(EXPORT:导出数据;IMPORT:导入模板) + */ + private Type type; + + /** + * 工作薄对象 + */ + private Workbook wb; + + /** + * 工作表对象 + */ + private Sheet sheet; + + /** + * 样式列表 + */ + private Map styles; + + /** + * 导入导出数据列表 + */ + private List list; + + /** + * 注解列表 + */ + private List fields; + + /** + * 当前行号 + */ + private int rownum; + + /** + * 标题 + */ + private String title; + + /** + * 最大高度 + */ + private short maxHeight; + + /** + * 合并后最后行数 + */ + private int subMergedLastRowNum = 0; + + /** + * 合并后开始行数 + */ + private int subMergedFirstRowNum = 1; + + /** + * 对象的子列表方法 + */ + private Method subMethod; + + /** + * 对象的子列表属性 + */ + private List subFields; + + /** + * 统计列表 + */ + private Map statistics = new HashMap(); + + /** + * 数字格式 + */ + private static final DecimalFormat DOUBLE_FORMAT = new DecimalFormat("######0.00"); + + /** + * 实体对象 + */ + public Class clazz; + + /** + * 需要排除列属性 + */ + public String[] excludeFields; + + public ProjectExcelUtil(Class clazz) { + this.clazz = clazz; + } + + /** + * 隐藏Excel中列属性 + * + * @param fields 列属性名 示例[单个"name"/多个"id","name"] + * @throws Exception + */ + public void hideColumn(String... fields) { + this.excludeFields = fields; + } + + public void init(List list, String sheetName, String title, Type type) { + if (list == null) { + list = new ArrayList(); + } + this.list = list; + this.sheetName = sheetName; + this.type = type; + this.title = title; + createExcelField(); + createWorkbook(); + createTitle(); + createSubHead(); + } + + /** + * 创建excel第一行标题 + */ + public void createTitle() { + if (StringUtils.isNotEmpty(title)) { + subMergedFirstRowNum++; + subMergedLastRowNum++; + int titleLastCol = this.fields.size() - 1; + if (isSubList()) { + titleLastCol = titleLastCol + subFields.size() - 1; + } + Row titleRow = sheet.createRow(rownum == 0 ? rownum++ : 0); + titleRow.setHeightInPoints(30); + Cell titleCell = titleRow.createCell(0); + titleCell.setCellStyle(styles.get("title")); + titleCell.setCellValue(title); + sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), titleRow.getRowNum(), titleLastCol)); + } + } + + /** + * 创建对象的子列表名称 + */ + public void createSubHead() { + if (isSubList()) { + subMergedFirstRowNum++; + subMergedLastRowNum++; + Row subRow = sheet.createRow(rownum); + int excelNum = 0; + for (Object[] objects : fields) { + Excel attr = (Excel) objects[1]; + Cell headCell1 = subRow.createCell(excelNum); + headCell1.setCellValue(attr.name()); + headCell1.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor()))); + excelNum++; + } + int headFirstRow = excelNum - 1; + int headLastRow = headFirstRow + subFields.size() - 1; + if (headLastRow > headFirstRow) { + sheet.addMergedRegion(new CellRangeAddress(rownum, rownum, headFirstRow, headLastRow)); + } + rownum++; + } + } + + /** + * 对excel表单默认第一个索引名转换成list + * + * @param is 输入流 + * @return 转换后集合 + */ + public List importExcel(InputStream is) { + List list = null; + try { + list = importExcel(is, 0); + } catch (Exception e) { + log.error("导入Excel异常{}", e.getMessage()); + throw new UtilException(e.getMessage()); + } finally { + IOUtils.closeQuietly(is); + } + return list; + } + + /** + * 对excel表单默认第一个索引名转换成list + * + * @param is 输入流 + * @param titleNum 标题占用行数 + * @return 转换后集合 + */ + public List importExcel(InputStream is, int titleNum) throws Exception { + return importExcel(StringUtils.EMPTY, is, titleNum); + } + + /** + * 对excel表单指定表格索引名转换成list + * + * @param sheetName 表格索引名 + * @param titleNum 标题占用行数 + * @param is 输入流 + * @return 转换后集合 + */ + public List importExcel(String sheetName, InputStream is, int titleNum) throws Exception { + this.type = Type.IMPORT; + this.wb = WorkbookFactory.create(is); + List list = new ArrayList(); + // 如果指定sheet名,则取指定sheet中的内容 否则默认指向第1个sheet + Sheet sheet = StringUtils.isNotEmpty(sheetName) ? wb.getSheet(sheetName) : wb.getSheetAt(0); + if (sheet == null) { + throw new IOException("文件sheet不存在"); + } + boolean isXSSFWorkbook = !(wb instanceof HSSFWorkbook); + Map pictures; + if (isXSSFWorkbook) { + pictures = getSheetPictures07((XSSFSheet) sheet, (XSSFWorkbook) wb); + } else { + pictures = getSheetPictures03((HSSFSheet) sheet, (HSSFWorkbook) wb); + } + // 获取最后一个非空行的行下标,比如总行数为n,则返回的为n-1 + int rows = sheet.getLastRowNum(); + if (rows > 0) { + // 定义一个map用于存放excel列的序号和field. + Map cellMap = new HashMap(); + // 获取表头 + Row heard = sheet.getRow(titleNum); + for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++) { + Cell cell = heard.getCell(i); + if (StringUtils.isNotNull(cell)) { + String value = this.getCellValue(heard, i).toString(); + cellMap.put(value, i); + } else { + cellMap.put(null, i); + } + } + // 有数据时才处理 得到类的所有field. + List fields = this.getFields(); + Map fieldsMap = new HashMap(); + List hasStr = new ArrayList<>(); + for (Object[] objects : fields) { + Excel attr = (Excel) objects[1]; + Integer column = cellMap.get(attr.name()); + if (column != null) { + hasStr.add(attr.name()); + fieldsMap.put(column, objects); + } + } + if(fieldsMap.size() != 4){ + throw new ServiceException("请导入正确的项目数据"); + } + for (int i = titleNum + 1; i <= rows; i++) { + // 从第2行开始取数据,默认第一行是表头. + Row row = sheet.getRow(i); + // 判断当前行是否是空行 + if (isRowEmpty(row)) { + continue; + } + T entity = null; + for (Map.Entry entry : fieldsMap.entrySet()) { + Object val = this.getCellValue(row, entry.getKey()); + + // 如果不存在实例则新建. + entity = (entity == null ? clazz.newInstance() : entity); + // 从map中得到对应列的field. + Field field = (Field) entry.getValue()[0]; + Excel attr = (Excel) entry.getValue()[1]; + // 取得类型,并根据对象类型设置值. + Class fieldType = field.getType(); + if (String.class == fieldType) { + String s = Convert.toStr(val); + if (StringUtils.endsWith(s, ".0")) { + val = StringUtils.substringBefore(s, ".0"); + } else { + String dateFormat = field.getAnnotation(Excel.class).dateFormat(); + if (StringUtils.isNotEmpty(dateFormat)) { + val = parseDateToStr(dateFormat, val); + } else { + val = Convert.toStr(val); + } + } + } else if ((Integer.TYPE == fieldType || Integer.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val))) { + val = Convert.toInt(val); + } else if ((Long.TYPE == fieldType || Long.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val))) { + val = Convert.toLong(val); + } else if (Double.TYPE == fieldType || Double.class == fieldType) { + val = Convert.toDouble(val); + } else if (Float.TYPE == fieldType || Float.class == fieldType) { + val = Convert.toFloat(val); + } else if (BigDecimal.class == fieldType) { + val = Convert.toBigDecimal(val); + } else if (Date.class == fieldType) { + if (val instanceof String) { + val = DateUtils.parseDate(val); + } else if (val instanceof Double) { + val = DateUtil.getJavaDate((Double) val); + } + } else if (Boolean.TYPE == fieldType || Boolean.class == fieldType) { + val = Convert.toBool(val, false); + } + if (StringUtils.isNotNull(fieldType)) { + String propertyName = field.getName(); + if (StringUtils.isNotEmpty(attr.targetAttr())) { + propertyName = field.getName() + "." + attr.targetAttr(); + } + if (StringUtils.isNotEmpty(attr.readConverterExp())) { + val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator()); + } else if (StringUtils.isNotEmpty(attr.dictType())) { + val = reverseDictByExp(Convert.toStr(val), attr.dictType(), attr.separator()); + } else if (!attr.handler().equals(ExcelHandlerAdapter.class)) { + val = dataFormatHandlerAdapter(val, attr, null); + } else if (ColumnType.IMAGE == attr.cellType() && StringUtils.isNotEmpty(pictures)) { + PictureData image = pictures.get(row.getRowNum() + "_" + entry.getKey()); + if (image == null) { + val = ""; + } else { + byte[] data = image.getData(); + val = FileUtils.writeImportBytes(data); + } + } + ReflectUtils.invokeSetter(entity, propertyName, val); + } + } + cellMap.entrySet().removeIf(entry -> hasStr.contains(entry.getKey())); + StringBuilder str = new StringBuilder(); + str.append("{"); + for (Map.Entry entry : cellMap.entrySet()) { + String key1 = entry.getKey(); + Object val1 = this.getCellValue(row, entry.getValue()); + if (val1 == "" || val1 == null) { + val1 = null; + str.append('"').append(key1).append('"').append(":").append(val1).append(","); + }else { + str.append('"').append(key1).append('"').append(":").append('"').append(val1).append('"').append(","); + } + } + str.append("}"); + String res = String.valueOf(str).replaceAll("\\s*|\r|\n|\t", ""); + ReflectUtils.invokeSetter(entity, "otherJson", res.replaceAll(",(?!.*,)","")); + list.add(entity); + } + } + return list; + } + + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @return 结果 + */ + public AjaxResult exportExcel(List list, String sheetName) { + return exportExcel(list, sheetName, StringUtils.EMPTY); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param title 标题 + * @return 结果 + */ + public AjaxResult exportExcel(List list, String sheetName, String title) { + this.init(list, sheetName, title, Type.EXPORT); + return exportExcel(); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param response 返回数据 + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @return 结果 + */ + public void exportExcel(HttpServletResponse response, List list, String sheetName) { + exportExcel(response, list, sheetName, StringUtils.EMPTY); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param response 返回数据 + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param title 标题 + * @return 结果 + */ + public void exportExcel(HttpServletResponse response, List list, String sheetName, String title) { + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding("utf-8"); + this.init(list, sheetName, title, Type.EXPORT); + exportExcel(response); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param sheetName 工作表的名称 + * @return 结果 + */ + public AjaxResult importTemplateExcel(String sheetName) { + return importTemplateExcel(sheetName, StringUtils.EMPTY); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param sheetName 工作表的名称 + * @param title 标题 + * @return 结果 + */ + public AjaxResult importTemplateExcel(String sheetName, String title) { + this.init(null, sheetName, title, Type.IMPORT); + return exportExcel(); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param sheetName 工作表的名称 + * @return 结果 + */ + public void importTemplateExcel(HttpServletResponse response, String sheetName) { + importTemplateExcel(response, sheetName, StringUtils.EMPTY); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param sheetName 工作表的名称 + * @param title 标题 + * @return 结果 + */ + public void importTemplateExcel(HttpServletResponse response, String sheetName, String title) { + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding("utf-8"); + this.init(null, sheetName, title, Type.IMPORT); + exportExcel(response); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @return 结果 + */ + public void exportExcel(HttpServletResponse response) { + try { + writeSheet(); + wb.write(response.getOutputStream()); + } catch (Exception e) { + log.error("导出Excel异常{}", e.getMessage()); + } finally { + IOUtils.closeQuietly(wb); + } + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @return 结果 + */ + public AjaxResult exportExcel() { + OutputStream out = null; + try { + writeSheet(); + String filename = encodingFilename(sheetName); + out = new FileOutputStream(getAbsoluteFile(filename)); + wb.write(out); + return AjaxResult.success(filename); + } catch (Exception e) { + log.error("导出Excel异常{}", e.getMessage()); + throw new UtilException("导出Excel失败,请联系网站管理员!"); + } finally { + IOUtils.closeQuietly(wb); + IOUtils.closeQuietly(out); + } + } + + /** + * 创建写入数据到Sheet + */ + public void writeSheet() { + // 取出一共有多少个sheet. + int sheetNo = Math.max(1, (int) Math.ceil(list.size() * 1.0 / sheetSize)); + for (int index = 0; index < sheetNo; index++) { + createSheet(sheetNo, index); + + // 产生一行 + Row row = sheet.createRow(rownum); + int column = 0; + // 写入各个字段的列头名称 + for (Object[] os : fields) { + Field field = (Field) os[0]; + Excel excel = (Excel) os[1]; + if (Collection.class.isAssignableFrom(field.getType())) { + for (Field subField : subFields) { + Excel subExcel = subField.getAnnotation(Excel.class); + this.createHeadCell(subExcel, row, column++); + } + } else { + this.createHeadCell(excel, row, column++); + } + } + if (Type.EXPORT.equals(type)) { + fillExcelData(index, row); + addStatisticsRow(); + } + } + } + + /** + * 填充excel数据 + * + * @param index 序号 + * @param row 单元格行 + */ + @SuppressWarnings("unchecked") + public void fillExcelData(int index, Row row) { + int startNo = index * sheetSize; + int endNo = Math.min(startNo + sheetSize, list.size()); + int rowNo = (1 + rownum) - startNo; + for (int i = startNo; i < endNo; i++) { + rowNo = isSubList() ? (i > 1 ? rowNo + 1 : rowNo + i) : i + 1 + rownum - startNo; + row = sheet.createRow(rowNo); + // 得到导出对象. + T vo = (T) list.get(i); + Collection subList = null; + if (isSubList()) { + if (isSubListValue(vo)) { + subList = getListCellValue(vo); + subMergedLastRowNum = subMergedLastRowNum + subList.size(); + } else { + subMergedFirstRowNum++; + subMergedLastRowNum++; + } + } + int column = 0; + for (Object[] os : fields) { + Field field = (Field) os[0]; + Excel excel = (Excel) os[1]; + if (Collection.class.isAssignableFrom(field.getType()) && StringUtils.isNotNull(subList)) { + boolean subFirst = false; + for (Object obj : subList) { + if (subFirst) { + rowNo++; + row = sheet.createRow(rowNo); + } + List subFields = FieldUtils.getFieldsListWithAnnotation(obj.getClass(), Excel.class); + int subIndex = 0; + for (Field subField : subFields) { + if (subField.isAnnotationPresent(Excel.class)) { + subField.setAccessible(true); + Excel attr = subField.getAnnotation(Excel.class); + this.addCell(attr, row, (T) obj, subField, column + subIndex); + } + subIndex++; + } + subFirst = true; + } + this.subMergedFirstRowNum = this.subMergedFirstRowNum + subList.size(); + } else { + this.addCell(excel, row, vo, field, column++); + } + } + } + } + + /** + * 创建表格样式 + * + * @param wb 工作薄对象 + * @return 样式列表 + */ + private Map createStyles(Workbook wb) { + // 写入各条记录,每条记录对应excel表中的一行 + Map styles = new HashMap(); + CellStyle style = wb.createCellStyle(); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + Font titleFont = wb.createFont(); + titleFont.setFontName("Arial"); + titleFont.setFontHeightInPoints((short) 16); + titleFont.setBold(true); + style.setFont(titleFont); + styles.put("title", style); + + style = wb.createCellStyle(); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setBorderRight(BorderStyle.THIN); + style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderLeft(BorderStyle.THIN); + style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderTop(BorderStyle.THIN); + style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderBottom(BorderStyle.THIN); + style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + Font dataFont = wb.createFont(); + dataFont.setFontName("Arial"); + dataFont.setFontHeightInPoints((short) 10); + style.setFont(dataFont); + styles.put("data", style); + + style = wb.createCellStyle(); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + Font totalFont = wb.createFont(); + totalFont.setFontName("Arial"); + totalFont.setFontHeightInPoints((short) 10); + style.setFont(totalFont); + styles.put("total", style); + + styles.putAll(annotationHeaderStyles(wb, styles)); + + styles.putAll(annotationDataStyles(wb)); + + return styles; + } + + /** + * 根据Excel注解创建表格头样式 + * + * @param wb 工作薄对象 + * @return 自定义样式列表 + */ + private Map annotationHeaderStyles(Workbook wb, Map styles) { + Map headerStyles = new HashMap(); + for (Object[] os : fields) { + Excel excel = (Excel) os[1]; + String key = StringUtils.format("header_{}_{}", excel.headerColor(), excel.headerBackgroundColor()); + if (!headerStyles.containsKey(key)) { + CellStyle style = wb.createCellStyle(); + style.cloneStyleFrom(styles.get("data")); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setFillForegroundColor(excel.headerBackgroundColor().index); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + Font headerFont = wb.createFont(); + headerFont.setFontName("Arial"); + headerFont.setFontHeightInPoints((short) 10); + headerFont.setBold(true); + headerFont.setColor(excel.headerColor().index); + style.setFont(headerFont); + headerStyles.put(key, style); + } + } + return headerStyles; + } + + /** + * 根据Excel注解创建表格列样式 + * + * @param wb 工作薄对象 + * @return 自定义样式列表 + */ + private Map annotationDataStyles(Workbook wb) { + Map styles = new HashMap(); + for (Object[] os : fields) { + Excel excel = (Excel) os[1]; + String key = StringUtils.format("data_{}_{}_{}", excel.align(), excel.color(), excel.backgroundColor()); + if (!styles.containsKey(key)) { + CellStyle style = wb.createCellStyle(); + style.setAlignment(excel.align()); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setBorderRight(BorderStyle.THIN); + style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderLeft(BorderStyle.THIN); + style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderTop(BorderStyle.THIN); + style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderBottom(BorderStyle.THIN); + style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + style.setFillForegroundColor(excel.backgroundColor().getIndex()); + Font dataFont = wb.createFont(); + dataFont.setFontName("Arial"); + dataFont.setFontHeightInPoints((short) 10); + dataFont.setColor(excel.color().index); + style.setFont(dataFont); + styles.put(key, style); + } + } + return styles; + } + + /** + * 创建单元格 + */ + public Cell createHeadCell(Excel attr, Row row, int column) { + // 创建列 + Cell cell = row.createCell(column); + // 写入列信息 + cell.setCellValue(attr.name()); + setDataValidation(attr, row, column); + cell.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor()))); + if (isSubList()) { + // 填充默认样式,防止合并单元格样式失效 + sheet.setDefaultColumnStyle(column, styles.get(StringUtils.format("data_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor()))); + if (attr.needMerge()) { + sheet.addMergedRegion(new CellRangeAddress(rownum - 1, rownum, column, column)); + } + } + return cell; + } + + /** + * 设置单元格信息 + * + * @param value 单元格值 + * @param attr 注解相关 + * @param cell 单元格信息 + */ + public void setCellVo(Object value, Excel attr, Cell cell) { + if (ColumnType.STRING == attr.cellType()) { + String cellValue = Convert.toStr(value); + // 对于任何以表达式触发字符 =-+@开头的单元格,直接使用tab字符作为前缀,防止CSV注入。 + if (StringUtils.startsWithAny(cellValue, FORMULA_STR)) { + cellValue = RegExUtils.replaceFirst(cellValue, FORMULA_REGEX_STR, "\t$0"); + } + if (value instanceof Collection && StringUtils.equals("[]", cellValue)) { + cellValue = StringUtils.EMPTY; + } + cell.setCellValue(StringUtils.isNull(cellValue) ? attr.defaultValue() : cellValue + attr.suffix()); + } else if (ColumnType.NUMERIC == attr.cellType()) { + if (StringUtils.isNotNull(value)) { + cell.setCellValue(StringUtils.contains(Convert.toStr(value), ".") ? Convert.toDouble(value) : Convert.toInt(value)); + } + } else if (ColumnType.IMAGE == attr.cellType()) { + ClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1), cell.getRow().getRowNum() + 1); + String imagePath = Convert.toStr(value); + if (StringUtils.isNotEmpty(imagePath)) { + byte[] data = ImageUtils.getImage(imagePath); + getDrawingPatriarch(cell.getSheet()).createPicture(anchor, + cell.getSheet().getWorkbook().addPicture(data, getImageType(data))); + } + } + } + + /** + * 获取画布 + */ + public static Drawing getDrawingPatriarch(Sheet sheet) { + if (sheet.getDrawingPatriarch() == null) { + sheet.createDrawingPatriarch(); + } + return sheet.getDrawingPatriarch(); + } + + /** + * 获取图片类型,设置图片插入类型 + */ + public int getImageType(byte[] value) { + String type = FileTypeUtils.getFileExtendName(value); + if ("JPG".equalsIgnoreCase(type)) { + return Workbook.PICTURE_TYPE_JPEG; + } else if ("PNG".equalsIgnoreCase(type)) { + return Workbook.PICTURE_TYPE_PNG; + } + return Workbook.PICTURE_TYPE_JPEG; + } + + /** + * 创建表格样式 + */ + public void setDataValidation(Excel attr, Row row, int column) { + if (attr.name().indexOf("注:") >= 0) { + sheet.setColumnWidth(column, 6000); + } else { + // 设置列宽 + sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256)); + } + if (StringUtils.isNotEmpty(attr.prompt()) || attr.combo().length > 0) { + if (attr.combo().length > 15 || StringUtils.join(attr.combo()).length() > 255) { + // 如果下拉数大于15或字符串长度大于255,则使用一个新sheet存储,避免生成的模板下拉值获取不到 + setXSSFValidationWithHidden(sheet, attr.combo(), attr.prompt(), 1, 100, column, column); + } else { + // 提示信息或只能选择不能输入的列内容. + setPromptOrValidation(sheet, attr.combo(), attr.prompt(), 1, 100, column, column); + } + } + } + + /** + * 添加单元格 + */ + public Cell addCell(Excel attr, Row row, T vo, Field field, int column) { + Cell cell = null; + try { + // 设置行高 + row.setHeight(maxHeight); + // 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列. + if (attr.isExport()) { + // 创建cell + cell = row.createCell(column); + if (isSubListValue(vo) && getListCellValue(vo).size() > 1 && attr.needMerge()) { + CellRangeAddress cellAddress = new CellRangeAddress(subMergedFirstRowNum, subMergedLastRowNum, column, column); + sheet.addMergedRegion(cellAddress); + } + cell.setCellStyle(styles.get(StringUtils.format("data_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor()))); + + // 用于读取对象中的属性 + Object value = getTargetValue(vo, field, attr); + String dateFormat = attr.dateFormat(); + String readConverterExp = attr.readConverterExp(); + String separator = attr.separator(); + String dictType = attr.dictType(); + if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value)) { + cell.setCellValue(parseDateToStr(dateFormat, value)); + } else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value)) { + cell.setCellValue(convertByExp(Convert.toStr(value), readConverterExp, separator)); + } else if (StringUtils.isNotEmpty(dictType) && StringUtils.isNotNull(value)) { + if (!sysDictMap.containsKey(dictType + value)) { + String lable = convertDictByExp(Convert.toStr(value), dictType, separator); + sysDictMap.put(dictType + value, lable); + } + cell.setCellValue(sysDictMap.get(dictType + value)); + } else if (value instanceof BigDecimal && -1 != attr.scale()) { + cell.setCellValue((((BigDecimal) value).setScale(attr.scale(), attr.roundingMode())).doubleValue()); + } else if (!attr.handler().equals(ExcelHandlerAdapter.class)) { + cell.setCellValue(dataFormatHandlerAdapter(value, attr, cell)); + } else { + // 设置列类型 + setCellVo(value, attr, cell); + } + addStatisticsData(column, Convert.toStr(value), attr); + } + } catch (Exception e) { + log.error("导出Excel失败{}", e); + } + return cell; + } + + /** + * 设置 POI XSSFSheet 单元格提示或选择框 + * + * @param sheet 表单 + * @param textlist 下拉框显示的内容 + * @param promptContent 提示内容 + * @param firstRow 开始行 + * @param endRow 结束行 + * @param firstCol 开始列 + * @param endCol 结束列 + */ + public void setPromptOrValidation(Sheet sheet, String[] textlist, String promptContent, int firstRow, int endRow, + int firstCol, int endCol) { + DataValidationHelper helper = sheet.getDataValidationHelper(); + DataValidationConstraint constraint = textlist.length > 0 ? helper.createExplicitListConstraint(textlist) : helper.createCustomConstraint("DD1"); + CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); + DataValidation dataValidation = helper.createValidation(constraint, regions); + if (StringUtils.isNotEmpty(promptContent)) { + // 如果设置了提示信息则鼠标放上去提示 + dataValidation.createPromptBox("", promptContent); + dataValidation.setShowPromptBox(true); + } + // 处理Excel兼容性问题 + if (dataValidation instanceof XSSFDataValidation) { + dataValidation.setSuppressDropDownArrow(true); + dataValidation.setShowErrorBox(true); + } else { + dataValidation.setSuppressDropDownArrow(false); + } + sheet.addValidationData(dataValidation); + } + + /** + * 设置某些列的值只能输入预制的数据,显示下拉框(兼容超出一定数量的下拉框). + * + * @param sheet 要设置的sheet. + * @param textlist 下拉框显示的内容 + * @param promptContent 提示内容 + * @param firstRow 开始行 + * @param endRow 结束行 + * @param firstCol 开始列 + * @param endCol 结束列 + */ + public void setXSSFValidationWithHidden(Sheet sheet, String[] textlist, String promptContent, int firstRow, int endRow, int firstCol, int endCol) { + String hideSheetName = "combo_" + firstCol + "_" + endCol; + Sheet hideSheet = wb.createSheet(hideSheetName); // 用于存储 下拉菜单数据 + for (int i = 0; i < textlist.length; i++) { + hideSheet.createRow(i).createCell(0).setCellValue(textlist[i]); + } + // 创建名称,可被其他单元格引用 + Name name = wb.createName(); + name.setNameName(hideSheetName + "_data"); + name.setRefersToFormula(hideSheetName + "!$A$1:$A$" + textlist.length); + DataValidationHelper helper = sheet.getDataValidationHelper(); + // 加载下拉列表内容 + DataValidationConstraint constraint = helper.createFormulaListConstraint(hideSheetName + "_data"); + // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列 + CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); + // 数据有效性对象 + DataValidation dataValidation = helper.createValidation(constraint, regions); + if (StringUtils.isNotEmpty(promptContent)) { + // 如果设置了提示信息则鼠标放上去提示 + dataValidation.createPromptBox("", promptContent); + dataValidation.setShowPromptBox(true); + } + // 处理Excel兼容性问题 + if (dataValidation instanceof XSSFDataValidation) { + dataValidation.setSuppressDropDownArrow(true); + dataValidation.setShowErrorBox(true); + } else { + dataValidation.setSuppressDropDownArrow(false); + } + + sheet.addValidationData(dataValidation); + // 设置hiddenSheet隐藏 + wb.setSheetHidden(wb.getSheetIndex(hideSheet), true); + } + + /** + * 解析导出值 0=男,1=女,2=未知 + * + * @param propertyValue 参数值 + * @param converterExp 翻译注解 + * @param separator 分隔符 + * @return 解析后值 + */ + public static String convertByExp(String propertyValue, String converterExp, String separator) { + StringBuilder propertyString = new StringBuilder(); + String[] convertSource = converterExp.split(","); + for (String item : convertSource) { + String[] itemArray = item.split("="); + if (StringUtils.containsAny(propertyValue, separator)) { + for (String value : propertyValue.split(separator)) { + if (itemArray[0].equals(value)) { + propertyString.append(itemArray[1] + separator); + break; + } + } + } else { + if (itemArray[0].equals(propertyValue)) { + return itemArray[1]; + } + } + } + return StringUtils.stripEnd(propertyString.toString(), separator); + } + + /** + * 反向解析值 男=0,女=1,未知=2 + * + * @param propertyValue 参数值 + * @param converterExp 翻译注解 + * @param separator 分隔符 + * @return 解析后值 + */ + public static String reverseByExp(String propertyValue, String converterExp, String separator) { + StringBuilder propertyString = new StringBuilder(); + String[] convertSource = converterExp.split(","); + for (String item : convertSource) { + String[] itemArray = item.split("="); + if (StringUtils.containsAny(propertyValue, separator)) { + for (String value : propertyValue.split(separator)) { + if (itemArray[1].equals(value)) { + propertyString.append(itemArray[0] + separator); + break; + } + } + } else { + if (itemArray[1].equals(propertyValue)) { + return itemArray[0]; + } + } + } + return StringUtils.stripEnd(propertyString.toString(), separator); + } + + /** + * 解析字典值 + * + * @param dictValue 字典值 + * @param dictType 字典类型 + * @param separator 分隔符 + * @return 字典标签 + */ + public static String convertDictByExp(String dictValue, String dictType, String separator) { + return DictUtils.getDictLabel(dictType, dictValue, separator); + } + + /** + * 反向解析值字典值 + * + * @param dictLabel 字典标签 + * @param dictType 字典类型 + * @param separator 分隔符 + * @return 字典值 + */ + public static String reverseDictByExp(String dictLabel, String dictType, String separator) { + return DictUtils.getDictValue(dictType, dictLabel, separator); + } + + /** + * 数据处理器 + * + * @param value 数据值 + * @param excel 数据注解 + * @return + */ + public String dataFormatHandlerAdapter(Object value, Excel excel, Cell cell) { + try { + Object instance = excel.handler().newInstance(); + Method formatMethod = excel.handler().getMethod("format", new Class[]{Object.class, String[].class, Cell.class, Workbook.class}); + value = formatMethod.invoke(instance, value, excel.args(), cell, this.wb); + } catch (Exception e) { + log.error("不能格式化数据 " + excel.handler(), e.getMessage()); + } + return Convert.toStr(value); + } + + /** + * 合计统计信息 + */ + private void addStatisticsData(Integer index, String text, Excel entity) { + if (entity != null && entity.isStatistics()) { + Double temp = 0D; + if (!statistics.containsKey(index)) { + statistics.put(index, temp); + } + try { + temp = Double.valueOf(text); + } catch (NumberFormatException e) { + } + statistics.put(index, statistics.get(index) + temp); + } + } + + /** + * 创建统计行 + */ + public void addStatisticsRow() { + if (statistics.size() > 0) { + Row row = sheet.createRow(sheet.getLastRowNum() + 1); + Set keys = statistics.keySet(); + Cell cell = row.createCell(0); + cell.setCellStyle(styles.get("total")); + cell.setCellValue("合计"); + + for (Integer key : keys) { + cell = row.createCell(key); + cell.setCellStyle(styles.get("total")); + cell.setCellValue(DOUBLE_FORMAT.format(statistics.get(key))); + } + statistics.clear(); + } + } + + /** + * 编码文件名 + */ + public String encodingFilename(String filename) { + filename = UUID.randomUUID() + "_" + filename + ".xlsx"; + return filename; + } + + /** + * 获取下载路径 + * + * @param filename 文件名称 + */ + public String getAbsoluteFile(String filename) { + String downloadPath = RuoYiConfig.getDownloadPath() + filename; + File desc = new File(downloadPath); + if (!desc.getParentFile().exists()) { + desc.getParentFile().mkdirs(); + } + return downloadPath; + } + + /** + * 获取bean中的属性值 + * + * @param vo 实体对象 + * @param field 字段 + * @param excel 注解 + * @return 最终的属性值 + * @throws Exception + */ + private Object getTargetValue(T vo, Field field, Excel excel) throws Exception { + Object o = field.get(vo); + if (StringUtils.isNotEmpty(excel.targetAttr())) { + String target = excel.targetAttr(); + if (target.contains(".")) { + String[] targets = target.split("[.]"); + for (String name : targets) { + o = getValue(o, name); + } + } else { + o = getValue(o, target); + } + } + return o; + } + + /** + * 以类的属性的get方法方法形式获取值 + * + * @param o + * @param name + * @return value + * @throws Exception + */ + private Object getValue(Object o, String name) throws Exception { + if (StringUtils.isNotNull(o) && StringUtils.isNotEmpty(name)) { + Class clazz = o.getClass(); + Field field = clazz.getDeclaredField(name); + field.setAccessible(true); + o = field.get(o); + } + return o; + } + + /** + * 得到所有定义字段 + */ + private void createExcelField() { + this.fields = getFields(); + this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList()); + this.maxHeight = getRowHeight(); + } + + /** + * 获取字段注解信息 + */ + public List getFields() { + List fields = new ArrayList(); + List tempFields = new ArrayList<>(); + tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields())); + tempFields.addAll(Arrays.asList(clazz.getDeclaredFields())); + for (Field field : tempFields) { + if (!ArrayUtils.contains(this.excludeFields, field.getName())) { + // 单注解 + if (field.isAnnotationPresent(Excel.class)) { + Excel attr = field.getAnnotation(Excel.class); + if (attr != null && (attr.type() == Type.ALL || attr.type() == type)) { + field.setAccessible(true); + fields.add(new Object[]{field, attr}); + } + if (Collection.class.isAssignableFrom(field.getType())) { + subMethod = getSubMethod(field.getName(), clazz); + ParameterizedType pt = (ParameterizedType) field.getGenericType(); + Class subClass = (Class) pt.getActualTypeArguments()[0]; + this.subFields = FieldUtils.getFieldsListWithAnnotation(subClass, Excel.class); + } + } + + // 多注解 + if (field.isAnnotationPresent(Excels.class)) { + Excels attrs = field.getAnnotation(Excels.class); + Excel[] excels = attrs.value(); + for (Excel attr : excels) { + if (!ArrayUtils.contains(this.excludeFields, field.getName() + "." + attr.targetAttr()) + && (attr != null && (attr.type() == Type.ALL || attr.type() == type))) { + field.setAccessible(true); + fields.add(new Object[]{field, attr}); + } + } + } + } + } + return fields; + } + + /** + * 根据注解获取最大行高 + */ + public short getRowHeight() { + double maxHeight = 0; + for (Object[] os : this.fields) { + Excel excel = (Excel) os[1]; + maxHeight = Math.max(maxHeight, excel.height()); + } + return (short) (maxHeight * 20); + } + + /** + * 创建一个工作簿 + */ + public void createWorkbook() { + this.wb = new SXSSFWorkbook(500); + this.sheet = wb.createSheet(); + wb.setSheetName(0, sheetName); + this.styles = createStyles(wb); + } + + /** + * 创建工作表 + * + * @param sheetNo sheet数量 + * @param index 序号 + */ + public void createSheet(int sheetNo, int index) { + // 设置工作表的名称. + if (sheetNo > 1 && index > 0) { + this.sheet = wb.createSheet(); + this.createTitle(); + wb.setSheetName(index, sheetName + index); + } + } + + /** + * 获取单元格值 + * + * @param row 获取的行 + * @param column 获取单元格列号 + * @return 单元格值 + */ + public Object getCellValue(Row row, int column) { + if (row == null) { + return row; + } + Object val = ""; + try { + Cell cell = row.getCell(column); + if (StringUtils.isNotNull(cell)) { + if (cell.getCellType() == CellType.NUMERIC || cell.getCellType() == CellType.FORMULA) { + val = cell.getNumericCellValue(); + if (DateUtil.isCellDateFormatted(cell)) { + val = DateUtil.getJavaDate((Double) val); // POI Excel 日期格式转换 + } else { + if ((Double) val % 1 != 0) { + val = new BigDecimal(val.toString()); + } else { + val = new DecimalFormat("0").format(val); + } + } + } else if (cell.getCellType() == CellType.STRING) { + val = cell.getStringCellValue(); + } else if (cell.getCellType() == CellType.BOOLEAN) { + val = cell.getBooleanCellValue(); + } else if (cell.getCellType() == CellType.ERROR) { + val = cell.getErrorCellValue(); + } + + } + } catch (Exception e) { + return val; + } + return val; + } + + /** + * 判断是否是空行 + * + * @param row 判断的行 + * @return + */ + private boolean isRowEmpty(Row row) { + if (row == null) { + return true; + } + for (int i = row.getFirstCellNum(); i < row.getLastCellNum(); i++) { + Cell cell = row.getCell(i); + if (cell != null && cell.getCellType() != CellType.BLANK) { + return false; + } + } + return true; + } + + /** + * 获取Excel2003图片 + * + * @param sheet 当前sheet对象 + * @param workbook 工作簿对象 + * @return Map key:图片单元格索引(1_1)String,value:图片流PictureData + */ + public static Map getSheetPictures03(HSSFSheet sheet, HSSFWorkbook workbook) { + Map sheetIndexPicMap = new HashMap(); + List pictures = workbook.getAllPictures(); + if (!pictures.isEmpty()) { + for (HSSFShape shape : sheet.getDrawingPatriarch().getChildren()) { + HSSFClientAnchor anchor = (HSSFClientAnchor) shape.getAnchor(); + if (shape instanceof HSSFPicture) { + HSSFPicture pic = (HSSFPicture) shape; + int pictureIndex = pic.getPictureIndex() - 1; + HSSFPictureData picData = pictures.get(pictureIndex); + String picIndex = anchor.getRow1() + "_" + anchor.getCol1(); + sheetIndexPicMap.put(picIndex, picData); + } + } + return sheetIndexPicMap; + } else { + return sheetIndexPicMap; + } + } + + /** + * 获取Excel2007图片 + * + * @param sheet 当前sheet对象 + * @param workbook 工作簿对象 + * @return Map key:图片单元格索引(1_1)String,value:图片流PictureData + */ + public static Map getSheetPictures07(XSSFSheet sheet, XSSFWorkbook workbook) { + Map sheetIndexPicMap = new HashMap(); + for (POIXMLDocumentPart dr : sheet.getRelations()) { + if (dr instanceof XSSFDrawing) { + XSSFDrawing drawing = (XSSFDrawing) dr; + List shapes = drawing.getShapes(); + for (XSSFShape shape : shapes) { + if (shape instanceof XSSFPicture) { + XSSFPicture pic = (XSSFPicture) shape; + XSSFClientAnchor anchor = pic.getPreferredSize(); + CTMarker ctMarker = anchor.getFrom(); + String picIndex = ctMarker.getRow() + "_" + ctMarker.getCol(); + sheetIndexPicMap.put(picIndex, pic.getPictureData()); + } + } + } + } + return sheetIndexPicMap; + } + + /** + * 格式化不同类型的日期对象 + * + * @param dateFormat 日期格式 + * @param val 被格式化的日期对象 + * @return 格式化后的日期字符 + */ + public String parseDateToStr(String dateFormat, Object val) { + if (val == null) { + return ""; + } + String str; + if (val instanceof Date) { + str = DateUtils.parseDateToStr(dateFormat, (Date) val); + } else if (val instanceof LocalDateTime) { + str = DateUtils.parseDateToStr(dateFormat, DateUtils.toDate((LocalDateTime) val)); + } else if (val instanceof LocalDate) { + str = DateUtils.parseDateToStr(dateFormat, DateUtils.toDate((LocalDate) val)); + } else { + str = val.toString(); + } + return str; + } + + /** + * 是否有对象的子列表 + */ + public boolean isSubList() { + return StringUtils.isNotNull(subFields) && subFields.size() > 0; + } + + /** + * 是否有对象的子列表,集合不为空 + */ + public boolean isSubListValue(T vo) { + return StringUtils.isNotNull(subFields) && subFields.size() > 0 && StringUtils.isNotNull(getListCellValue(vo)) && getListCellValue(vo).size() > 0; + } + + /** + * 获取集合的值 + */ + public Collection getListCellValue(Object obj) { + Object value; + try { + value = subMethod.invoke(obj, new Object[]{}); + } catch (Exception e) { + return new ArrayList(); + } + return (Collection) value; + } + + /** + * 获取对象的子列表方法 + * + * @param name 名称 + * @param pojoClass 类对象 + * @return 子列表方法 + */ + public Method getSubMethod(String name, Class pojoClass) { + StringBuffer getMethodName = new StringBuffer("get"); + getMethodName.append(name.substring(0, 1).toUpperCase()); + getMethodName.append(name.substring(1)); + Method method = null; + try { + method = pojoClass.getMethod(getMethodName.toString(), new Class[]{}); + } catch (Exception e) { + log.error("获取对象异常{}", e.getMessage()); + } + return method; + } +} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/MyBatisConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/MyBatisConfig.java index 057c941..40b37fb 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/MyBatisConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/MyBatisConfig.java @@ -1,20 +1,13 @@ package com.ruoyi.framework.config; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import javax.sql.DataSource; -import org.apache.ibatis.io.VFS; -import org.apache.ibatis.session.SqlSessionFactory; -import org.mybatis.spring.SqlSessionFactoryBean; -import org.mybatis.spring.boot.autoconfigure.SpringBootVFS; +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; -import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; @@ -22,11 +15,16 @@ import org.springframework.core.type.classreading.CachingMetadataReaderFactory; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.util.ClassUtils; -import com.ruoyi.common.utils.StringUtils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; /** * Mybatis支持*匹配扫描包 - * + * * @author ruoyi */ @Configuration @@ -114,19 +112,10 @@ public class MyBatisConfig } @Bean - public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception - { - String typeAliasesPackage = env.getProperty("mybatis.typeAliasesPackage"); - String mapperLocations = env.getProperty("mybatis.mapperLocations"); - String configLocation = env.getProperty("mybatis.configLocation"); - typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage); - VFS.addImplClass(SpringBootVFS.class); - - final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); - sessionFactory.setDataSource(dataSource); - sessionFactory.setTypeAliasesPackage(typeAliasesPackage); - sessionFactory.setMapperLocations(resolveMapperLocations(StringUtils.split(mapperLocations, ","))); - sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation)); - return sessionFactory.getObject(); + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); + interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); + return interceptor; } } \ No newline at end of file diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java index 2125853..fa328ff 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java @@ -115,6 +115,9 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter // 静态资源,可匿名访问 .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll() .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll() + .antMatchers("/jjh/**").permitAll() + + // 除上面外的所有请求全部需要鉴权认证 .anyRequest().authenticated() .and()