首页
友链
统计
留言
关于
Search
1
网站声明
55 阅读
2
Java生成二维码——基于Google插件
55 阅读
3
Java使用poi-tl动态生成word和pdf
36 阅读
4
循环单链表及其实现
31 阅读
5
双链表及其实现
31 阅读
默认分类
Java
C语言
数据库技术
Linux
前端
其他
登录
/
注册
Search
标签搜索
C语言
数据结构
Java
Spring
数据库技术
MySQL
设计模式
策略模式
工厂模式
IDEA
SpringMVC
AOP
MybatisPlus
POI
easyExcel
LiXiangrong
累计撰写
56
篇文章
累计收到
4
条评论
首页
栏目
默认分类
Java
C语言
数据库技术
Linux
前端
其他
页面
友链
统计
留言
关于
搜索到
10
篇与
的结果
2024-04-15
springboot整合easyExcel导出excel
1. 引入依赖<!--excel读写--> <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>3.3.2</version> </dependency>2.导出工具public class ExportUtil { public static final Logger LOGGER = LoggerFactory.getLogger(ExportUtil.class); private static final String WORD = ".docx"; private static final String PDF = ".pdf"; private static final String XLSX = ".xlsx"; private static final String TYPE = "application/octet-stream"; private static final String HEADER_K = "Content-disposition"; private static final String HEADER_V = "attachment;filename="; /** * @Author LiXiangrong * @Description 导出Excel到web流 * @Date 2024/04/02 9:37:07 * @param clazz 导出目标类 * @param response 浏览器响应 * @param fileName 文件名末尾会自动拼上导出时间 * @param sheetName sheetName * @param dataList 数据集合 * @Return void **/ public static void exportExcel(Class<?> clazz, HttpServletResponse response, String fileName,String sheetName, List<?> dataList) { try { String DateTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy年MM月dd日HH时mm分ss秒")); fileName = URLEncoder.encode(fileName+DateTime,"UTF-8").replaceAll("\\+", "%20"); response.setContentType("application/vnd.ms-excel"); response.setCharacterEncoding("utf-8"); response.setHeader(HEADER_K, "attachment;filename*=utf-8''" + fileName + XLSX); EasyExcel.write(response.getOutputStream(),clazz) .excelType(ExcelTypeEnum.XLSX) .sheet(sheetName) .doWrite(dataList); } catch (IOException e) { e.printStackTrace(); LOGGER.error("导出{}Excel失败",fileName, e); throw new DataException("导出Excel失败"); } } }3.在控制层查询导出数据并使用导出工具导出到web@ApiOperation("XXX导出") @PostMapping("/xxxExport") public void exportExcel(HttpServletResponse response,@RequestBody JProjectSupervisePagination jProjectSupervisePagination) { jProjectSupervisePagination.setDataType("1"); //无需分页 List<JProjectSuperviseEntity> list = jProjectSuperviseService.getList(jProjectSupervisePagination); //处理id字段转名称,若无需转或者为空可删除 List<HPGExportVO> listVO = JsonUtil.getJsonToList(list, HPGExportVO.class); for (HPGExportVO exportVO : listVO) { JTopicLibraryEntity jTopicLibraryEntity = jProjectSuperviseService.getJTopicLibrary(exportVO.getTopicId()); if (Objects.nonNull(jTopicLibraryEntity)) { exportVO.setTopicName(jTopicLibraryEntity.getTopicName()); exportVO.setUpdatedBy(generaterSwapUtil.userSelectValues(exportVO.getUpdatedBy())); } } ExportUtil.exportExcel(HPGExportVO.class, response, "任务后评估", "任务后评估", listVO); }3.常用注解// 导出字段注解,value为表头名,index为顺序,从0开始,如果不指定则按照字段顺序导出 @ExcelProperty(value = "任务编码",index = 0) // 无需导出 @ExcelIgnore4.前端导出方法 methods: { exportExcel() { let data = { ...this.listQuery, ...this.query, keyword: this.keyword, dataType: 0, menuId: this.menuId, moduleId: '426394122396395781', sourceType: '3' } downloadExcel('/api/szyd/JProjectSupervise/hpgExport', data, { fileName: '任务后评估导出' }) }, }5.前端导出工具// excel文件导出 export function downloadExcel(url, data = {}, options = {}) { const fileName = `${options.fileName || 'file'}-${getCurrentDateTime()}.xlsx` const hideNotify = options.hideNotify || false return new Promise((resolve, reject) => { !hideNotify && Notification({ title: "导出中", message: "正在导出一份电子表格", iconClass: "el-icon-loading", duration: 2000 }) request({ url, method: "post", data, responseType: "blob" }).then(file => { downloadFileByBlob(file, fileName) resolve(file) }).catch(err => { reject(err) }) }) } // Blob下载文件 export function downloadFileByBlob (content, filename) { let eleLink = document.createElement("a"); eleLink.download = filename; eleLink.style.display = "none"; let blob = new Blob([content]); eleLink.href = URL.createObjectURL(blob); document.body.appendChild(eleLink); eleLink.click(); document.body.removeChild(eleLink); }6.导出到本地或指定位置EasyExcel.write("D:\\Tencent Files\\处理分析结果.xlsx") .head(ExcelWriteData.class) .excelType(ExcelTypeEnum.XLSX).sheet("Sheet1").doWrite(readList);
2024年04月15日
4 阅读
0 评论
0 点赞
2024-01-25
Java使用poi-tl动态生成word和pdf
1.导入依赖,注意版本必须匹配详情参见官网 poi-tl官方文档<!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!--导出word--> <dependency> <groupId>com.deepoove</groupId> <artifactId>poi-tl</artifactId> <version>1.10.5</version> </dependency> <!--xpwf转pdf(根据word导出pdf)--> <dependency> <groupId>fr.opensagres.xdocreport</groupId> <artifactId>fr.opensagres.poi.xwpf.converter.pdf-gae</artifactId> <version>2.0.2</version> </dependency> <!--SpringEL表达式--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>5.3.18</version> </dependency> <!-- https://mvnrepository.com/artifact/io.github.draco1023/poi-tl-ext --> <!--富文本解析--> <dependency> <groupId>io.github.draco1023</groupId> <artifactId>poi-tl-ext</artifactId> <version>0.3.22</version> <exclusions> <exclusion> <groupId>com.deepoove</groupId> <artifactId>poi-tl</artifactId> </exclusion> <exclusion> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> </exclusion> </exclusions> </dependency>2.准备文件模板{{data.id}} {{data.sno}} {{data.name}} {{data.sex}} {{data.age}} {{data.createTime}} 图片解析 {{@data.img}} 富文本 {{data.content}} SpringEL表达式对时间格式化 {{data.createTime == null ? "" : new java.text.SimpleDateFormat('yyyy-MM-dd').format(data.createTime)}} 字符串集合遍历 {{?data.list}} {{=#this}} {{/data.list}} 复杂对象集合遍历和取值 {{?data.cityList}} {{id}} {{name}} {{/data.cityList}} 3.生成文件到本地@Test public void test() { Student entity = new Student(); entity.setId("1"); entity.setSno("1"); entity.setName("张三"); entity.setSex("男"); entity.setAge(25); entity.setCreateTime(new Date()); final ArrayList<String> strings = new ArrayList<>(); strings.add("str1"); strings.add("str2"); strings.add("str3"); entity.setList(strings); // Base64图片 String base64Str = "这里填写Base64编码的图片字符串,此处限于篇幅省略"; entity.setImg(Pictures.ofBase64(base64Str, PictureType.JPEG).size(96, 45).create()); // 网络图片 // entity.setImg("https://www.lxrao.com/myfile/cat.jpg"); // 富文本 entity.setContent("此处粘贴富文本,此处限于篇幅省略"); List<City> list = new ArrayList<>(); City city1 = new City(); city1.setId(1); city1.setName("BeiJing"+"\n"); list.add(city1); City city2 = new City(); city2.setId(1); city2.setName("ShangHai"); list.add(city2); entity.setCityList(list); try(InputStream inputStream = getClass().getResourceAsStream("/templates/test.docx")) { Assert.isTrue(Objects.nonNull(inputStream),"模板不存在!"); HashMap<String,Object> map = new HashMap<>(); map.put("data",entity); // 富文本解析 HtmlRenderPolicy htmlRenderPolicy = new HtmlRenderPolicy(); Configure configure = Configure.builder().bind("data.content", htmlRenderPolicy).useSpringEL().build(); XWPFTemplate template = XWPFTemplate.compile(inputStream,configure).render(map); // 1.导出word文件 template.writeAndClose(new FileOutputStream("C:\\Users\\LiXiangrong\\Desktop\\test.docx")); // 2.导出pdf文件 PdfOptions options = PdfOptions.create(); FileOutputStream outPDF = new FileOutputStream("C:\\Users\\LiXiangrong\\Desktop\\test.pdf"); PdfConverter.getInstance().convert(template.getXWPFDocument(), outPDF, options); outPDF.close(); } catch (IOException e) { System.out.println(e.getMessage()); } }4.下载到web端package com.example.springbootdemo.utils; import com.deepoove.poi.XWPFTemplate; import fr.opensagres.poi.xwpf.converter.pdf.PdfConverter; import fr.opensagres.poi.xwpf.converter.pdf.PdfOptions; import org.springframework.util.Assert; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.HashMap; import java.util.Objects; public class ExportUtil { private static final String WORD = ".docx"; private static final String PDF = ".pdf"; private static final String TYPE = "application/octet-stream"; public static void exportWordOrPDF(HttpServletResponse response,Object o,String tempName,String exportName,String fileType) { final String fileSuffix = "word".equals(fileType) ? WORD : PDF; // 赋值数据对象 HashMap<String,Object> map = new HashMap<>(); map.put("data",o); // 读取模板文件 InputStream inputStream = ExportUtil.class.getResourceAsStream("/templates/"+tempName); Assert.isTrue(Objects.nonNull(inputStream),"模板文件不存在!"); XWPFTemplate template = XWPFTemplate.compile(inputStream).render(map); // 生成文件 response.setContentType(TYPE); try { response.setHeader("Content-disposition", "attachment;filename="+ URLEncoder.encode(exportName+fileSuffix, "UTF-8")); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } try { OutputStream outputStream = response.getOutputStream(); if ("word".equals(fileType)) { template.writeAndClose(outputStream); } else { PdfOptions options = PdfOptions.create(); PdfConverter.getInstance().convert(template.getXWPFDocument(), outputStream, options); outputStream.close(); } } catch (IOException e) { throw new RuntimeException("导出异常!"); } } }5.控制层接口@GetMapping("/exportPDF") public void exportPDF(HttpServletResponse response) { Student entity = new Student(); entity.setId("1"); entity.setSno("1"); entity.setName("张三"); entity.setSex("男"); entity.setAge(25); ExportUtil.exportWordOrPDF(response,entity,"test.docx","导出pdf测试","pdf"); } @GetMapping("/exportWORD") public void exportWORD(HttpServletResponse response) { Student entity = new Student(); entity.setId("1"); entity.setSno("1"); entity.setName("张三"); entity.setSex("男"); entity.setAge(25); ExportUtil.exportWordOrPDF(response,entity,"test.docx","导出word测试","word"); }6.浏览器地址栏输入url测试7.前端下载方法<el-button type="primary" @click="downloadToWord" :loading="downloadLoading">下载</el-button>下载公共方法写在工具类中// Blob下载文件 export function downloadFileByBlob (content, filename) { let eleLink = document.createElement("a"); eleLink.download = filename; eleLink.style.display = "none"; let blob = new Blob([content]); eleLink.href = URL.createObjectURL(blob); document.body.appendChild(eleLink); eleLink.click(); document.body.removeChild(eleLink); }下载方法放在methods:{}中import { downloadFileByBlob } from '@/utils' // Loading downloadLoading: false, downloadToWord() { const { id } = this.topicsInfo this.downloadLoading = true request({ url: `/api/szyd/JTopicRequestMeeting/export`, method: 'get', responseType: "blob", data: { id, type: 'word', temp: this.curTemp, exportName: 'test' } }).then(file => { this.$message({ message: '文件下载成功', type: 'success' }) downloadFileByBlob(file, document.title + '.docx') }).finally(() => { this.downloadLoading = false }) },
2024年01月25日
36 阅读
0 评论
0 点赞
2024-01-12
由MybatisPlus配置类未生效引出的问题到SpringBoot复写Bean
1.在某微服务项目中,测试提出一个缺陷:在列表输入框选择条件,不点击查询而是点击翻页,点击后页面刷新,按照条件筛选出数据数量但不显示数据,其实,本质上就是分页查询的页号溢出问题。由于该项目使用的是MybatisPlus,要解决这个问题其实只要写一个MybatisPlus配置类,中设置一个属性即可。 2.但是发现这个配置类设置的这个属性值未生效,在启动类中获取bean发现这个属性依然是false,注释掉这个Bean后发现依然存在这个Bean,这时候就找到在该项目的jar包中已经存在这个Bean导致自己写的Bean未生效。 3.于是思路就是要重写这个Bean,可以实现Spring中的接口:Bean定义注册后置处理器BeanDefinitionRegistryPostProcessor。代码如下:MybatisPlusMyConfigpackage jnpf.config; import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * MyBatisPlus配置 */ @Configuration public class MybatisPlusMyConfig { /** * @Author LiXiangrong * @Description 复写MybatisPlusInterceptor * @Date 2024/01/11 18:04:33 * @Return com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor **/ @Bean("mybatisPlusInterceptor1") public MybatisPlusInterceptor mybatisPlusInterceptor() { // 核心插件 MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 添加分页插件(如果配置多个插件,切记分页最后添加) PaginationInnerInterceptor innerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL); // dbType(数据库类型) innerInterceptor.setOverflow(true); // 默认值:false。溢出总页数后是否进行处理。 interceptor.addInnerInterceptor(innerInterceptor); return interceptor; } }MyBeanDefinitionRegistryPostProcessorpackage jnpf.config; import org.jetbrains.annotations.NotNull; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.stereotype.Component; /** * @Author LiXiangrong * @Description 自定义的Bean定义注册后置处理器 * @Date 2024/01/11 18:06:08 **/ @Component public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor { @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { String bean1 = "mybatisPlusInterceptor"; String bean2 = "mybatisPlusInterceptor1"; // 复写MybatisPlusInterceptor // 若jar包和程序都注册了mybatisPlusInterceptor,就将程序里的bd覆盖掉jar包里的bd(继续使用jar包里的beanName,防止jar包中其它bean指定依赖了这个beanName) if (registry.containsBeanDefinition(bean1) && registry.containsBeanDefinition(bean2)) { // 移除bean1,用bean2注册一个新的bean1,然后把bean2移除(复写了bean1) registry.removeBeanDefinition(bean1); registry.registerBeanDefinition(bean1, registry.getBeanDefinition(bean2)); registry.removeBeanDefinition(bean2); } } @Override public void postProcessBeanFactory(@NotNull ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { } }
2024年01月12日
20 阅读
0 评论
0 点赞
2024-01-03
AOP实现防止前端请求重复提交
1.防止重复提交注解package com.risesun.common.core.annotation; import java.lang.annotation.*; /** * @Author LiXiangrong * @Description 防止重复提交注解 * @Date 2023/04/03 9:04:15 **/ @Inherited @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface RepeatSubmit { /** * 防重复操作限时标记数值(存储redis限时标记数值) */ String value() default "value" ; /** * 防重复操作过期时间(借助redis实现限时控制) */ long expireSeconds() default 10; }2.AOP实现防止请求重复提交package com.risesun.business.aspect; import cn.hutool.crypto.digest.DigestUtil; import cn.hutool.json.JSONUtil; import com.risesun.common.core.annotation.RepeatSubmit; import com.risesun.common.core.constant.TokenConstants; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Method; import java.util.Objects; import java.util.concurrent.TimeUnit; /** * @Author LiXiangrong * @Description AOP实现防止请求重复提交 * @Date 2023/04/03 8:41:04 **/ @Slf4j @Component @Aspect public class NoRepeatSubmitAspect { @Autowired private RedisTemplate redisTemplate; private final String SIGN = "submit duplication"; private final String PREFIX = "PREVENT_DUPLICATION_PREFIX:"; /** * @Author LiXiangrong * @Description 定义切点 * @Date 2023/04/03 8:53:11 * @Return void **/ @Pointcut("@annotation(com.risesun.common.core.annotation.RepeatSubmit)") public void preventDuplication() {} /** * @Author LiXiangrong * @Description 环绕方法 * @Date 2023/04/03 8:52:50 * @Param pjp * @Return java.lang.Object **/ @Around("NoRepeatSubmitAspect.preventDuplication()") public Object around(ProceedingJoinPoint pjp) throws Throwable { // 获取请求信息 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); // 获取执行方法 Method method = ((MethodSignature) pjp.getSignature()).getMethod(); //获取防重复提交注解 RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class); // 获取authorization以及方法标记,生成redisKey和redisValue String authorization = request.getHeader(TokenConstants.AUTHENTICATION); String url = request.getRequestURI(); // 通过前缀 + url + token + 函数参数签名 来生成redis上的 key String redisKey = PREFIX.concat(url).concat(authorization).concat(getMethodSign(method, pjp.getArgs())); // 判断redisTemplate是否存在标记,如果没有,则是首次提交该请求,需要把设置标记并且正常返回 if (!redisTemplate.hasKey(redisKey) && Objects.nonNull(annotation)) { // 这个值只是为了标记,不重要 String redisValue = redisKey.concat(annotation.value()).concat(SIGN); // 设置防重复操作的限时标记(前置通知) redisTemplate.opsForValue().set(redisKey, redisValue, annotation.expireSeconds(), TimeUnit.SECONDS); try { // 正常执行方法并返回 ProceedingJoinPoint类型参数可以决定是否执行目标方法, // 环绕通知必须要有返回值,返回值即为目标方法的返回值 return pjp.proceed(); } catch (Throwable throwable) { //确保方法执行异常实时释放限时标记(异常后置通知) redisTemplate.delete(redisKey); throw throwable; } } else { throw new RuntimeException("数据正在处理,请勿重复提交!"); } } /** * @Author LiXiangrong * @Description 获取方法签名生成方法标记,采用数字签名算法SHA1对方法签名字符串加签 * @Date 2023/04/03 8:49:45 * @Param method * @Param args * @Return java.lang.String **/ private String getMethodSign(Method method, Object... args) { StringBuilder sb = new StringBuilder(method.toString()); for (Object arg : args) { sb.append(toString(arg)); } return DigestUtil.sha1Hex(sb.toString()); } /** * @Author LiXiangrong * @Description 对参数重写toString方法,避免空参造成的影响 * @Date 2023/04/03 8:50:58 * @Param arg * @Return java.lang.String **/ private String toString(Object arg) { if (Objects.isNull(arg)) { return "null"; } if (arg instanceof Number) { return arg.toString(); } return JSONUtil.toJsonStr(arg); } }
2024年01月03日
15 阅读
0 评论
0 点赞
2024-01-03
MybatisPlus自动填充字段值
package com.risesun.business.hander; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import org.apache.ibatis.reflection.MetaObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import com.risesun.common.security.utils.SecurityUtils; import java.util.Date; /** * @Author LiXiangrong * @Description 兼容MybatisPlus自动填充字段值 * @Date 2023/06/01 14:33:37 **/ @Component public class MybatisPlusHandler implements MetaObjectHandler { public static final Logger LOGGER = LoggerFactory.getLogger(MybatisPlusHandler.class); @Override public void insertFill(MetaObject metaObject) { LOGGER.info("MybatisPlusHandler开始自动填充创建时间、创建人属性值..."); this.setFieldValByName("createBy", SecurityUtils.getUsername(),metaObject); this.setFieldValByName("createTime",new Date(),metaObject); } @Override public void updateFill(MetaObject metaObject) { LOGGER.info("MybatisPlusHandler开始自动填充更新时间、更新人属性值..."); this.setFieldValByName("updateBy",SecurityUtils.getUsername(),metaObject); this.setFieldValByName("updateTime",new Date(),metaObject); } }
2024年01月03日
3 阅读
0 评论
0 点赞
1
2