首页
友链
统计
留言
关于
Search
1
Java使用poi-tl动态生成word和pdf
207 阅读
2
Java生成二维码——基于Google插件
146 阅读
3
实现MyBatis拦截器自动填充创建、更新时间等字段属性值
113 阅读
4
利用Spring的InitializingBean优雅的实现策略模式
112 阅读
5
网站声明
110 阅读
默认分类
Java
C语言
数据库技术
Linux
前端
其他
登录
/
注册
Search
标签搜索
C语言
数据结构
Java
Spring
数据库技术
MySQL
Hadoop
MapReduce
大数据
easyExcel
POI
MybatisPlus
AOP
SpringMVC
IDEA
工厂模式
策略模式
设计模式
LiXiangrong
累计撰写
57
篇文章
累计收到
214
条评论
首页
栏目
默认分类
Java
C语言
数据库技术
Linux
前端
其他
页面
友链
统计
留言
关于
搜索到
57
篇与
的结果
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日
207 阅读
36 评论
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日
57 阅读
0 评论
0 点赞
2024-01-06
二叉树的非递归遍历和相关运算
#include <stdio.h> #include <stdlib.h> // 7.4.3 二叉树的非递归遍历 typedef char dataType; typedef struct treeNode { dataType data; // 数据域 struct treeNode *lChild,*rChild; // 左、右孩子指针域 }node,*binaryTree; // 顺序栈 #define MAX_SIZE 100 typedef struct stack { node *data[MAX_SIZE]; // 栈中存放的是二叉树结点指针 int top; // 栈顶指针 }seqStack; // 顺序循环队列:用于层序(层次)遍历 typedef struct { node *data[MAX_SIZE]; int front,rear; // 队头、队尾指针 }queue; // 1.栈初始化 void initStack(seqStack *stack) { stack->top = 0; } // 2. 判断栈是否为空 int emptyStack(seqStack stack) { return stack.top == 0; } // 3. 入栈 void push(seqStack *stack, node* n) { if(stack->top == MAX_SIZE-1) { printf("栈已满,无法入栈!\n"); exit(1); } stack->data[stack->top++] = n; } // 4. 读取栈顶元素 node *get(seqStack stack) { return stack.data[stack.top-1]; } // 5. 出栈 node* pop(seqStack *stack) { if(emptyStack(*stack)) { printf("栈已空,无法出栈!\n"); exit(1); } return stack->data[--stack->top]; } // 6.队列初始化 void initQueue(queue *q) { q->front = q->rear = 0; } // 7.判断队列是否为空 int emptyQueue(queue q) { return q.rear == q.front; } // 8.入队 void enQueue(queue *q, node *n) { if((q->rear+1)%MAX_SIZE == q->front) { printf("队列满,无法入队!\n"); exit(1); } q->data[q->rear] = n; q->rear = (q->rear + 1)%MAX_SIZE; } // 9.出队 node *deQueue(queue *q) { if(emptyQueue(*q)) { printf("队列为空,无法出队!\n"); exit(1); } node *n = q->data[q->front]; q->front = (q->front+1)%MAX_SIZE; return n; } // 10. 按照前序遍历的顺序创建一个二叉树 binaryTree createTree() { binaryTree t; char c; if((c = getchar()) == '#') t = NULL; else { t = (node *) malloc(sizeof(node)); t->data = c; t->lChild = createTree(); t->rChild = createTree(); } return t; } // 11. 非递归前序遍历 void preOrder(binaryTree t) { seqStack stack; // 声明顺序栈 stack.top = 0; // 初始化栈 while (t || !emptyStack(stack)) // 树非空或栈非空 { if(t) // 一路向左直到左孩子为空 { printf("%c ",t->data); // 先访问根节点 push(&stack,t); t = t->lChild; // 再访问左孩子 } else { t = pop(&stack); t = t->rChild; // 再访问右孩子 } } } // 12.非递归中序遍历 void inOrder(binaryTree t) { seqStack stack; // 声明顺序栈 stack.top = 0; // 初始化栈 while (t || !emptyStack(stack)) { if(t) // 一路向左直到左孩子为空 { push(&stack,t); t = t->lChild; } else { t = pop(&stack); printf("%c ",t->data); t = t->rChild; } } } // 13.非递归后序遍历 void postOrder(binaryTree t) { seqStack stack; // 声明顺序栈 stack.top = 0; // 初始化栈 node *r = NULL; // 记录最近访问的结点 while (t || !emptyStack(stack)) { if (t) // 一路向左直到左孩子为空 { push(&stack,t); // 沿着根的左孩子依次入栈 t = t->lChild; } else { t = stack.data[stack.top-1]; // 读取栈顶元素 if(t->rChild && t->rChild != r) // 右孩子存在且未访问 t = t->rChild; // 转向右孩子 else { pop(&stack); // 出栈 printf("%c ", t->data); r = t; // 记录最近访问的结点(关键步骤) t = NULL; // 结点访问后重置为空(关键步骤) } } } } // 14. 二叉树层次遍历 seqStack nodeStack; void levelOrder(binaryTree t) { if(!t) { printf("二叉树为空!\n"); return; } queue q; // 声明队列 initQueue(&q); // 初始化队列 enQueue(&q,t); // 根节点入队 initStack(&nodeStack); while (!emptyQueue(q)) // 队列非空 { t = deQueue(&q);; // 出队并访问 push(&nodeStack,t); printf("%c ",t->data); if(t->lChild) // 左孩子入队 enQueue(&q,t->lChild); if(t->rChild) // 右孩子入队 enQueue(&q,t->rChild); } } // 15. 非递归求二叉树层数(深度或高度) int level(binaryTree t) { queue q; // 声明队列 initQueue(&q); // 初始化队列 int level = 0, first = 0; // first指向每层最左侧结点 if(!t) return 0; enQueue(&q,t); // 根结点入队 while (!emptyQueue(q)) // 队列非空 { if(first == q.front) // 当队首结点是某层的第一个结点时 { level++; // 层数累加 first = q.rear; // 更新first指针指向下一层的第一个结点位置 } t = deQueue(&q); // 出队并将孩子结点入队 if(t->lChild) // 左孩子入队 enQueue(&q,t->lChild); if(t->rChild) // 右孩子入队 enQueue(&q,t->rChild); } return level; } // 16.非递归求二叉树最大宽度 int width(binaryTree t) { queue q; // 声明循环队列 initQueue(&q); // 初始化队列 int i = 1, width = 0, first = 0; // i初值为1,处理只有一个结点的树 if(!t) return 0; // 树为空时 enQueue(&q,t); // 根节点入队 while (!emptyQueue(q)) // 队列非空时 { if(first == q.front) // 当first指向每层第一个节点时 { if(i > width) width = i; // 更新最大宽度 first = q.rear; // 更新first指针 i = 0; // 重置i,以计算该层宽度 } t = deQueue(&q); // 元素出队 i++; // 计算该层宽度 if(t->lChild) enQueue(&q,t->lChild); // 左孩子入队 if(t->rChild) enQueue(&q,t->rChild); // 右孩子入队 } return width; } // 17.返回二叉树任意两结点p、q的共同祖先 node *seekAncestor(binaryTree t, node *p, node *q) { seqStack s, s1; // 声明顺序栈 initStack(&s), initStack(&s1); // 初始化栈 node *r = NULL; // 记录最近访问的结点 while (t || !emptyStack(s)) { if (t) // 一路向左直到左孩子为空 { push(&s,t); // 沿着根的左孩子依次入栈 t = t->lChild; } else { t = get(s); // 读取栈顶元素 if (t->rChild && t->rChild != r) // 右孩子存在且未访问 t = t->rChild; // 转向右孩子 else { pop(&s); // 出栈 if (t == p || t == q) { if (emptyStack(s1)) for (int i = s.top - 1; i >= 0; i--) push(&s1, s.data[i]); else break; } r = t; // 记录最近访问的结点(关键步骤) t = NULL; // 结点访问后重置为空(关键步骤) } } } while (!emptyStack(s)) { t = pop(&s); for (int j = s1.top-1; j >= 0; j--) if(t == s1.data[j]) return t; } return NULL; } int main() { binaryTree t; // 声明二叉树 printf("请输入结点,创建一颗二叉树,#表示空结点:\n"); t = createTree(); // ABD#E##FG###C## printf("前序遍历\n"); preOrder(t); printf("\n中序遍历\n"); inOrder(t); printf("\n后序遍历\n"); postOrder(t); printf("\n层序遍历\n"); levelOrder(t); printf("\n树的高度为%d", level(t)); node *p = nodeStack.data[2], *q = nodeStack.data[6], *n; n = seekAncestor(t,p,q); if(n) printf("\n结点%c和结点%c的共同祖先是%c",p->data,q->data,n->data); else printf("\n结点%c和结点%c没有共同祖先",p->data,q->data); printf("\n该二叉树的宽度为%d", width(t)); return 0;
2024年01月06日
22 阅读
0 评论
0 点赞
2024-01-05
链式队列及其实现
#include <stdio.h> #include <stdlib.h> typedef int dataType; // 3.7 链式队列 typedef struct linkQueueNode { dataType data; struct linkQueueNode *next; }node,*linkQueue; // 链式队列头指针和尾指针 typedef struct { linkQueue front,rear; }queue; // 1.初始化链式队列 void init(queue *qu) { qu->front = qu->rear = NULL; } // 2.判断队列是否为空 int empty(queue qu) { return !qu.front; } // 3.读队首元素的值 dataType read(queue qu) { if(empty(qu)) { printf("队列为空!\n"); exit(1); } return qu.front->data; } // 4.输出队列元素的值 void display(queue qu) { node *p = qu.front; if(!p) { printf("队列为空!\n"); return; } while (p) { printf("%d ",p->data); p = p->next; } printf("\n"); } // 5.入队 void insert(queue *qu, dataType x) { node *q; q = (node*) malloc(sizeof(node)); q->data = x; q->next = NULL; if(empty(*qu)) // 队列为空时 qu->front = q; else qu->rear->next = q; qu->rear = q; // 更新尾指针 } // 6.出队 void del(queue *qu) { node *p = qu->front; if(p == qu->rear) // 只有一个结点或队列空 { if(!p) { printf("队列为空,无法出队!\n"); return; } qu->front = qu->rear; // 更新头指针 free(p); return; } // 队列非空时更新队头指针并释放结点空间 qu->front = p->next; free(p); } int main() { queue qu; // 定义一个指向队列的头指针和尾指针 init(&qu); // 初始化队列 display(qu); // 输出队列元素 printf("入队!\n"); for (int i = 1; i <= 5; i++) insert(&qu,i); // 入队 display(qu); printf("队首元素为%d\n",read(qu)); printf("出队!\n"); del(&qu); display(qu); return 0; }
2024年01月05日
53 阅读
0 评论
0 点赞
2024-01-05
链式栈及其实现
#include <stdio.h> #include <stdlib.h> typedef int dataType; // 3.6 链式栈 typedef struct linkStackNode { dataType data; struct linkStackNode *next; }node,*linkStack; // 1.初始化链式栈 void init(linkStack *top) { *top = NULL; } // 2.判断栈是否为空 int empty(linkStack top) { return !top; } // 3. 读取栈顶结点 node *read(linkStack top) { return top; } // 4.输出链式栈中各结点值 void display(linkStack top) { if(!top) { printf("栈空,无法输出结点!\n"); return; } while (top) { printf("%d ",top->data); top = top->next; } printf("\n"); } // 5.入栈 void push(linkStack *top, dataType x) { node *q = (node*) malloc(sizeof(node)); q->data = x; q->next = *top; // 新结点放在栈顶元素上面 *top = q; // 栈顶指针指向新结点 } // 6.出栈 void pop(linkStack *top) { if(!*top) { printf("栈空,无法出栈!\n"); return; } node *p = *top; *top = p->next; // 更新栈顶指针 free(p); } int main() { linkStack top; // 声明一个栈顶指针 init(&top); // 初始化链式栈 display(top); // 输出栈中各元素的值 dataType a = 1,b = 2; printf("元素%d入栈\n",a); push(&top,a); // 入栈 display(top); printf("元素%d入栈\n",b); push(&top,b); display(top); printf("出栈\n"); pop(&top); // 出栈 display(top); return 0; }
2024年01月05日
59 阅读
0 评论
0 点赞
1
...
6
7
8
...
12