当前位置: 首页 > news >正文

电子签章Java后端与前端交互签名位置计算

电子签章过程中存在着在网页上对签署文件进行预览、指定签署位置、文件签署等操作,由于图片在浏览器上的兼容性和友好性优于PDF文件,所以一般在网页上进行电子签章时,会先将PDF文件转换成图片,展示给用户。用户在页面上确定好签署位置,并进行签署时,后端服务会通过对电子印章/手写签名位置、大小以及PDF文件的大小进行计算,在PDF文件的准确位置上完成文件签署。以下代码是Java后端与前端交互签名位置计算的源代码,希望对大家有帮助。

更多电子签章前后端交互体验,可访问开源网站获取电子签章/电子合同工具源码:

https://gitee.com/kaifangqian

https://github.com/kaifangqian

关联工具包:itext-pdf;

1、计算签署配置业务类;

import com.itextpdf.text.Document;
import com.itextpdf.text.pdf.PdfReader;
import com.resrun.service.pojo.RealPositionProperty;
import com.resrun.service.pojo.SelectKeywords;
import com.resrun.service.pojo.SourcePositionProperty;
import org.springframework.stereotype.Service;import java.io.IOException;
import java.util.ArrayList;
import java.util.List;/*** @Description: 计算签署位置业务* @Package: com.resrun.service.pdf* @ClassName: CalculatePositionService* @copyright 北京资源律动科技有限公司*/
@Service
public class CalculatePositionService {/*** @Description #批量计算真实签署位置* @Param [sourcePositionProperties]* @return java.util.List<com.resrun.modules.sign.service.tool.pojo.RealPositionProperty>**/public List<RealPositionProperty> calculatePositions(List<SourcePositionProperty> sourcePositionProperties, byte[] pdfFileByte){List<RealPositionProperty> realPositionProperties = new ArrayList<>();PdfReader reader = null ;try {//将pdf文件读入PdfReader工具类reader = new PdfReader(pdfFileByte);for(SourcePositionProperty sourcePositionProperty : sourcePositionProperties){RealPositionProperty realPositionProperty = calculatePosition(sourcePositionProperty,pdfFileByte);Document document = new Document(reader.getPageSize(sourcePositionProperty.getPage()));//获取真实pdf文件指定页的真实文档宽高float realPdfHeight = document.getPageSize().getHeight();float realPdfWidth = document.getPageSize().getWidth();//获取页面上文档的宽高float sourcePageWidth = sourcePositionProperty.getPageWidth();float sourcePageHeight = sourcePositionProperty.getPageHeight();//计算真实文档的宽高和页面文档的宽高的比率float rateHeight = realPdfHeight / sourcePageHeight;float rateWidth = realPdfWidth / sourcePageWidth;//计算页面上的横纵坐标,由于页面上给出的是左上角的坐标,所以需要再转换计算一下//左下角float pageStartX = sourcePositionProperty.getOffsetX();float pageStartY = sourcePositionProperty.getOffsetY() + sourcePositionProperty.getHeight() ;//右上角float pageEndX = sourcePositionProperty.getOffsetX() + sourcePositionProperty.getWidth();float pageEndY = sourcePositionProperty.getOffsetY();//根据比率去计算真实文档上的坐标位置float startX = pageStartX * rateWidth ;float startY = pageStartY * rateHeight;float endX = pageEndX * rateWidth ;float endY = pageEndY * rateHeight ;//由于页面的纵坐标和pdf的纵坐标是相反的,所以真实的pdf的纵坐标在计算的时候需要再反转一下startY = realPdfHeight - startY ;endY = realPdfHeight - endY ;//封装返回数据realPositionProperty.setStartx(startX);realPositionProperty.setStarty(startY);realPositionProperty.setEndx(endX);realPositionProperty.setEndy(endY);realPositionProperty.setPageNum(sourcePositionProperty.getPage());document.close();realPositionProperties.add(realPositionProperty);}reader.close();} catch (Exception e) {e.printStackTrace();}return realPositionProperties ;}/*** @Description #单独计算真实签署位置* @Param [sourcePositionProperty]* @return com.resrun.modules.sign.service.tool.pojo.RealPositionProperty**/public RealPositionProperty calculatePosition(SourcePositionProperty sourcePositionProperty, byte[] pdfFileByte){RealPositionProperty realPositionProperty = new RealPositionProperty();PdfReader reader = null ;Document document = null ;try {//将pdf文件读入PdfReader工具类reader = new PdfReader(pdfFileByte);document = new Document(reader.getPageSize(sourcePositionProperty.getPage()));//获取真实pdf文件指定页的真实文档宽高float realPdfHeight = document.getPageSize().getHeight();float realPdfWidth = document.getPageSize().getWidth();//获取页面上文档的宽高float sourcePageWidth = sourcePositionProperty.getPageWidth();float sourcePageHeight = sourcePositionProperty.getPageHeight();//计算真实文档的宽高和页面文档的宽高的比率float rateHeight = realPdfHeight / sourcePageHeight;float rateWidth = realPdfWidth / sourcePageWidth;//计算页面上的横纵坐标,由于页面上给出的是左上角的坐标,所以需要再转换计算一下//左下角float pageStartX = sourcePositionProperty.getOffsetX();float pageStartY = sourcePositionProperty.getOffsetY() + sourcePositionProperty.getHeight() ;//右上角float pageEndX = sourcePositionProperty.getOffsetX() + sourcePositionProperty.getWidth();float pageEndY = sourcePositionProperty.getOffsetY();//根据比率去计算真实文档上的坐标位置float startX = pageStartX * rateWidth ;float startY = pageStartY * rateHeight;float endX = pageEndX * rateWidth ;float endY = pageEndY * rateHeight ;//由于页面的纵坐标和pdf的纵坐标是相反的,所以真实的pdf的纵坐标在计算的时候需要再反转一下startY = realPdfHeight - startY ;endY = realPdfHeight - endY ;//封装返回数据realPositionProperty.setStartx(startX);realPositionProperty.setStarty(startY);realPositionProperty.setEndx(endX);realPositionProperty.setEndy(endY);realPositionProperty.setPageNum(sourcePositionProperty.getPage());document.close();reader.close();} catch (Exception e) {e.printStackTrace();}return realPositionProperty ;}public RealPositionProperty calculatePosition(SourcePositionProperty sourcePositionProperty){RealPositionProperty realPositionProperty = new RealPositionProperty();//获取真实pdf文件指定页的真实文档宽高float realPdfHeight = sourcePositionProperty.getRealHeight();float realPdfWidth = sourcePositionProperty.getRealWidth();//获取页面上文档的宽高float sourcePageWidth = sourcePositionProperty.getPageWidth();float sourcePageHeight = sourcePositionProperty.getPageHeight();//计算真实文档的宽高和页面文档的宽高的比率float rateHeight = realPdfHeight / sourcePageHeight;float rateWidth = realPdfWidth / sourcePageWidth;//计算页面上的横纵坐标,由于页面上给出的是左上角的坐标,所以需要再转换计算一下//左下角float pageStartX = sourcePositionProperty.getOffsetX();float pageStartY = sourcePositionProperty.getOffsetY() + sourcePositionProperty.getHeight() ;//右上角float pageEndX = sourcePositionProperty.getOffsetX() + sourcePositionProperty.getWidth();float pageEndY = sourcePositionProperty.getOffsetY();//根据比率去计算真实文档上的坐标位置float startX = pageStartX * rateWidth ;float startY = pageStartY * rateHeight;float endX = pageEndX * rateWidth ;float endY = pageEndY * rateHeight ;//由于页面的纵坐标和pdf的纵坐标是相反的,所以真实的pdf的纵坐标在计算的时候需要再反转一下startY = realPdfHeight - startY ;endY = realPdfHeight - endY ;//封装返回数据realPositionProperty.setStartx(startX);realPositionProperty.setStarty(startY);realPositionProperty.setEndx(endX);realPositionProperty.setEndy(endY);realPositionProperty.setPageNum(sourcePositionProperty.getPage());return realPositionProperty ;}/*** 通过查询关键字来获得签名位置信息* @param pdfFile 签署源文件* @param keyWords 关键字* @param width 签章宽度* @param height 签章高度* @return 签署位置信息* @throws IOException*/public RealPositionProperty getPositionByKeyWords(byte[] pdfFile, String keyWords, int width, int height) {RealPositionProperty positionProperty = new RealPositionProperty();//调用通过关键字查询位置的方法float[] result = new float[0];try {result = new SelectKeywords().selectKeyword(pdfFile,keyWords);} catch (Exception e) {e.printStackTrace();}if(result !=null){positionProperty.setStartx(result[0]);positionProperty.setStarty(result[1]+height/4);positionProperty.setPageNum((int)result[2]);positionProperty.setEndx(result[0]+width/2);positionProperty.setEndy(result[1]-height/4);}return positionProperty;}/*** 通过查询关键字来获得签名位置信息<br/>** 同一个关键字出现在多处会一次性全部找出** @param pdfFile 签署源文件* @param keyWords 关键字* @param width 签章宽度* @param height 签章高度* @return 签署位置信息* @throws IOException*/public List<RealPositionProperty> getAllPositionByKeyWords(byte[] pdfFile,String keyWords,int width,int height) {List<RealPositionProperty> positions = new ArrayList<RealPositionProperty>();//调用通过关键字查询位置的方法List<float[]> results = null;try {results = new SelectKeywords().selectAllKeyword(pdfFile, keyWords);} catch (Exception e) {e.printStackTrace();}if(results !=null && results.size()>0){for (float[] result : results) {RealPositionProperty positionProperty = new RealPositionProperty();positionProperty.setStartx(result[0]);positionProperty.setStarty(result[1]+height/4);positionProperty.setPageNum((int)result[2]);positionProperty.setEndx(result[0]+width/2);positionProperty.setEndy(result[1]-height/4);positions.add(positionProperty);}}return positions;}}

2、计算后的签名位置信息类;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.io.Serializable;/*** @Description: 经过计算后的文件签署位置属性类* @Package: com.resrun.service.pojo* @ClassName: PositionProperty* @copyright 北京资源律动科技有限公司*/
@AllArgsConstructor
@NoArgsConstructor
@Data
public class RealPositionProperty implements Serializable {private static final long serialVersionUID = 8586984409612483553L;/** 签章左下角x坐标 */private  float startx;/** 签章左下角y坐标*/private  float starty;/** 签章右上角x坐标*/private  float endx;/** 签章右上角x坐标*/private  float endy;private  int pageNum;// 填写值,填写专用private String value ;//对齐方式private String align ;//字体private String fontFamily ;//文字大小private Integer fontSize ;
}

3、关键字位置计算类;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import org.apache.pdfbox.text.TextPosition;import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;/*** @Description: 关键字计算位置* @Package: com.resrun.service.pojo* @ClassName: SelectKeywords* @copyright 北京资源律动科技有限公司*/
public class SelectKeywords extends PDFTextStripper {private static ThreadLocal<KeyWorkPair> keyWorkPair = new ThreadLocal<KeyWorkPair>();private Log logger = LogFactory.getLog(SelectKeywords.class);public SelectKeywords() throws IOException {super.setSortByPosition(true);}//    public static void main(String[] args) throws Exception {
//        //selectKeyword
//        File file = new File("e:/test/948ad938bab14f4e8a2d843f6dd81d57.pdf");
//        float [] resus = new SelectKeywords().selectKeyword(IOUtils.toByteArray(file), "948ad938bab14f4e8a2d843f6dd81d57");//66   571
//        System.out.println(resus[0]+"--"+resus[1]+"---"+resus[2]);
//    }/*** 查出PDF里所有的关键字* @param pdfFile* @param KEY_WORD* @return*/public List<float[]> selectAllKeyword(byte [] pdfFile, String KEY_WORD) {keyWorkPair.set(new KeyWorkPair(KEY_WORD.split(",")));ByteArrayInputStream in = null;PDDocument document = null;try {in = new ByteArrayInputStream(pdfFile);document = PDDocument.load(in);//加载pdf文件this.getText(document);List<float[]> allResu = getAllResult();return allResu;} catch (Exception e) {e.printStackTrace();}finally{try {if(in!=null) in.close();if(document!=null) document.close();} catch (IOException e) {}}return null;}private List<float[]> getAllResult(){KeyWorkPair pair = keyWorkPair.get();if(pair!=null && pair.getResu()!=null){keyWorkPair.set(null);return pair.getAllResu();}else{keyWorkPair.set(null);return null;}}/*** 查出PDF里最后一个关键字* @param pdfFile* @param KEY_WORD* @return*/public float [] selectKeyword(byte [] pdfFile,String KEY_WORD) {keyWorkPair.set(new KeyWorkPair(KEY_WORD.split(",")));ByteArrayInputStream in = null;PDDocument document = null;try {in = new ByteArrayInputStream(pdfFile);document = PDDocument.load(in);//加载pdf文件this.getText(document);float[] resu = getResult();return resu;} catch (Exception e) {e.printStackTrace();}finally{try {if(in!=null) in.close();if(document!=null) document.close();} catch (IOException e) {}}return null;}private float[] getResult(){KeyWorkPair pair = keyWorkPair.get();if(pair!=null && pair.getResu()!=null){keyWorkPair.set(null);return pair.getResu();}else{keyWorkPair.set(null);return null;}}@Overrideprotected void writeString(String string, List<TextPosition> textPositions) throws IOException {for (TextPosition text : textPositions) {String tChar = text.toString();char c = tChar.charAt(0);String REGEX = "[,.\\[\\](:;!?)/]";lineMatch = matchCharLine(text);if ((!tChar.matches(REGEX)) && (!Character.isWhitespace(c))) {if ((!is1stChar) && (lineMatch == true)) {appendChar(tChar);} else if (is1stChar == true) {setWordCoord(text, tChar);}} else {endWord();}}endWord();}protected void appendChar(String tChar) {tWord.append(tChar);is1stChar = false;}/**** %拼接字符串%。*/protected void setWordCoord(TextPosition text, String tChar) {itext = text;tWord.append("(").append(pageNo).append(")[").append(roundVal(Float.valueOf(text.getXDirAdj()))).append(" : ").append(roundVal(Float.valueOf(text.getYDirAdj()))).append("] ").append(tChar);is1stChar = false;}protected boolean matchCharLine(TextPosition text) {Double yVal = roundVal(Float.valueOf(text.getYDirAdj()));if (yVal.doubleValue() == lastYVal) {return true;}lastYVal = yVal.doubleValue();endWord();return false;}protected Double roundVal(Float yVal) {DecimalFormat rounded = new DecimalFormat("0.0'0'");Double yValDub = new Double(rounded.format(yVal));return yValDub;}protected void endWord() {// String newWord = tWord.toString().replaceAll("[^\\x00-\\x7F]",// "");//为了检索速度 使用正则去掉中文String newWord = tWord.toString();// 去掉正则 可以检索中文KeyWorkPair pair = keyWorkPair.get();try {String[] seekA = pair.getSeekA();float[] resu = new float[3];String sWord = newWord.substring(newWord.lastIndexOf(' ') + 1);if (!"".equals(sWord)) {if (sWord.contains(seekA[0])) {resu[2] = getCurrentPageNo();// (595,842)resu[0] = (float) (roundVal(Float.valueOf(itext.getXDirAdj())) + 0.0F);resu[1] = 842.0F - (float) (roundVal(Float.valueOf(itext.getYDirAdj())) + 0.0F);logger.info("PDF关键字信息:[页数:" + resu[2] + "][X:" + resu[0] + "][Y:" + resu[1] + "]");pair.setResu(resu);pair.addResuList(resu);//把每一次找出的关键字放在一个集合里keyWorkPair.set(pair);}}} catch (Exception e) {e.printStackTrace();keyWorkPair.set(null);throw new RuntimeException();}tWord.delete(0, tWord.length());is1stChar = true;}private StringBuilder tWord = new StringBuilder();private boolean is1stChar = true;private boolean lineMatch;private int pageNo = 0;private double lastYVal;private TextPosition itext;/*** 关键字和返回的位置信息类*/class KeyWorkPair {public KeyWorkPair(String[] seekA) {super();this.seekA = seekA;}public KeyWorkPair(String[] seekA, float[] resu) {super();this.seekA = seekA;this.resu = resu;}public KeyWorkPair() {super();}public String[] getSeekA() {return seekA;}public void setSeekA(String[] seekA) {this.seekA = seekA;}public float[] getResu() {return resu;}public void setResu(float[] resu) {this.resu = resu;}public void addResuList(float[] resu) {resuAll.add(resu);}public List<float[]> getAllResu() {return resuAll;}private String[] seekA;private float[] resu;//所有的位置private List<float[]> resuAll = new ArrayList<>();}
}

4、原始文件签署位置信息类;

import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.io.Serializable;/*** @Description: 原始文件签署位置属性* @Package: com.resrun.service.pojo* @ClassName: SourcePositionProperty* @copyright 北京资源律动科技有限公司*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SourcePositionProperty implements Serializable {private static final long serialVersionUID = 725976764583634367L;@ApiModelProperty("控件X坐标(左上角)")private Float offsetX ;@ApiModelProperty("控件Y坐标(左上角)")private Float offsetY ;@ApiModelProperty("控件宽度")private Float width ;@ApiModelProperty("控件高度")private Float height ;@ApiModelProperty("当前文件页面宽度")private Float pageWidth ;@ApiModelProperty("当前文件页面高度")private Float pageHeight ;@ApiModelProperty("控件所属页码")private Integer page ;@ApiModelProperty("当前文件页面宽度")private Float realWidth ;@ApiModelProperty("当前文件页面高度")private Float realHeight ;}

相关文章:

电子签章Java后端与前端交互签名位置计算

电子签章过程中存在着在网页上对签署文件进行预览、指定签署位置、文件签署等操作&#xff0c;由于图片在浏览器上的兼容性和友好性优于PDF文件&#xff0c;所以一般在网页上进行电子签章时&#xff0c;会先将PDF文件转换成图片&#xff0c;展示给用户。用户在页面上确定好签署…...

为什么选择嬴图?

图数据库、图计算、图中台都是用图论的方式去构造实体间的关联关系&#xff0c;实体用顶点来表达&#xff0c;而实体间的关系用边来表达。图数据库的这种简洁、自由、高维但100%还原世界的数据建模的方式让实体间的关联关系的计算比SQL类的数据库高效成千上万倍。 图&#xff1…...

Python学习之路-编码风格

Python学习之路-编码风格 设计哲学 Python的设计哲学是“优雅”、“明确”、“简单”。它的重要准则被称为“Python之禅”。Python之禅又名PEP 20&#xff0c;在Python解释器内运行import this可以获得完整的列表&#xff0c;下面是我的翻译与解读&#xff1a; 提姆彼得斯&a…...

权威认可!甄知科技猪齿鱼产品荣获信创产品评估证书

近日&#xff0c;依据《信息技术应用创新产品评估规范 第1部分&#xff1a;应用软件》&#xff08;T/SSIA 2001-2022&#xff09;&#xff0c;经过严格评估&#xff0c;甄知科技旗下自主研发的猪齿鱼数智化开发管理平台 V2.0.0&#xff0c;通过信创测试认证&#xff0c;获得上海…...

9. 回文数(Java)

题目描述&#xff1a; 给你一个整数 x &#xff0c;如果 x 是一个回文整数&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 回文数是指正序&#xff08;从左向右&#xff09;和倒序&#xff08;从右向左&#xff09;读都是一样的整数。 例如&#xff0c;121 …...

Python(30):非对称加密算法RSA的使用(openssl生成RSA公私钥对)

Python(30)&#xff1a;非对称加密算法RSA的使用(openssl生成RSA公私钥对) 1、openssl生成RSA公私钥对 1.1、生成RSA公私钥对命令 [rootloaclhost ~]# openssl OpenSSL> genrsa -out rsa_private_key.pem 1024 Generating RSA private key, 1024 bit long modulus .. ...…...

Java学习笔记-day04-NIO核心依赖多路复用小记

NIO允许一个线程同时处理多个连接&#xff0c;而不会因为一个连接的阻塞而导致其他连接被阻塞。核心是依赖操作系统的多路复用机制。 操作系统的多路复用机制 多路复用是一种操作系统的 I/O 处理机制&#xff0c;允许单个进程&#xff08;或线程&#xff09;同时监视多个输入…...

Java+springboot+vue智慧校园源码,数据云平台Web端+小程序教师端+小程序家长端

技术架构&#xff1a; Javaspringbootvue element-ui小程序电子班牌&#xff1a;Java Android演示自主版权。 智慧校园电子班牌人脸识别系统全套源码&#xff0c;包含&#xff1a;数据云平台Web端小程序教师端小程序家长端电子班牌 学生端。 电子班牌系统又称之为智慧班牌&am…...

算法日志的存在核心在于搭建自检系统

"相信每一个人执行与日志有关的任务都会遇到这样难题吧&#xff1f;长达几万行的日志&#xff0c;如果我们单纯用肉眼去一个个排查&#xff0c;那么恐怕所耗费的时间是以天为计量单位了。当然这是一种比较夸张的情况&#xff0c;根据我的项目经验&#xff0c;正常情况是十…...

【2023开发组一等奖】定位家乡味——北京市老乡探店寻味系统

作品介绍 1 需求分析 中国人的身上都系着两根线,一条线牵引着我们去远方,一条线牵引着我们归故乡。在当今社会,我们因为各种各样的原因背起行囊远离故乡去往千里之外的远方,而那暗涌在血脉的乡愁总会使我们在看到家乡菜的时候,心底溢出一种不可言说的温暖。那么,当你在异…...

37-数据类型,一元运算符typeof,字符串string,布尔Boolean,未定义undefined,空null,数组Array

<body><script>// 0.1加0.2不等于0.3&#xff0c;正确的运算方法如下console.log(0.10.2);var x 0.1;var y 0.2;console.log((x*10y*10)/10);</script> </body> 简单数据类型&#xff08;5种&#xff09;&#xff1a;数字number&#xff0c;字符串s…...

zabbix部署

zabbix部署 部署zabbix服务被监测主机部署zabbix-agent2 使用版本 组件版本centos7.9zabbix5.0php7.2.24MariaDB5.5.68 部署zabbix服务 关闭防火墙和selinux [rootnode ~]# systemctl status firewalld ● firewalld.service - firewalld - dynamic firewall daemonLoaded: …...

深入理解Java源码:提升技术功底,深度掌握技术框架,快速定位线上问题

为什么要看源码&#xff1a; 1、提升技术功底&#xff1a; 学习源码里的优秀设计思想&#xff0c;比如一些疑难问题的解决思路&#xff0c;还有一些优秀的设计模式&#xff0c;整体提升自己的技术功底 2、深度掌握技术框架&#xff1a; 源码看多了&#xff0c;对于一个新技术…...

寒假前端第一次作业

1、用户注册&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>用户注册</title> …...

【LabVIEW FPGA入门】创建第一个LabVIEW FPGA程序

本教程仅以compactRIO&#xff08;FPGA-RT&#xff09;举例 1.系统配置 1.1软件安装 FPGA-RT 1. LabVIEW Development System (Full or Professional) 2. LabVIEW Real-Time Module 3. LabVIEW FPGA Module 4. NI-RIO drivers 1.2硬件配置 1.使用线缆连接CompactRIO至主机…...

【STM32】STM32学习笔记-USART串口数据包(28)

00. 目录 文章目录 00. 目录01. 串口简介02. HEX数据包03. 文本数据包04. HEX数据包接收05. 文本数据包接收06. 预留07. 附录 01. 串口简介 串口通讯(Serial Communication)是一种设备间非常常用的串行通讯方式&#xff0c;因为它简单便捷&#xff0c;因此大部分电子设备都支持…...

Java网络爬虫--HttpClient

目录标题 技术介绍有什么优点&#xff1f;怎么在项目中引入&#xff1f; 请求URLEntityUtils 类GET请求带参数的GET请求POST请求 总结 技术介绍 HttpClient 是 Apache Jakarta Common 下的子项目&#xff0c;用来提供高效的、功能丰富的、支持 HTTP 协议的客户端编程工具包。相…...

若依项目的table列表中对每一个字段增加排序按钮(单体版和前后端分离版)

一、目标:每一个字段都添加上下箭头用来排序 只需要更改前端代码,不需要更改后端代码,后面会讲解原理 二、单体版实现方式: 1.在options中添加sortable:true 2.在需要排序的字段中添加sortable:true 三、前后端分离版 1.el-table上添加@sort-change=“handleSortChange”…...

Linux自动化部署脚本

1:最近项目部署比较频繁终于熬不住了 就有下面的这东西 #!/bin/sh #报错停止运行 set -e # 获取tomcat的PID TOMCAT_PID$(ps -ef | grep tomcat | grep -v grep | awk {print $2}) # tomcat的启动文件位置 START_TOMCAT/mnt/tomcat/bin/startup.sh # 项目文件部署位置 PROJECT…...

lvgl修改图片大小上限

在lvgl中读取图片文件时&#xff0c;被读取的图片具有上限&#xff0c;也就是2048像素。这会造成两个非预期的结果&#xff1a; 超过2048像素的部分会被裁去。表示图片的结构体lv_img_t中的w和h变量值是图片像素被2048求余。例如&#xff0c;当一个图片高为2048像素时&#xf…...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写&#xff0c;中文译为后进先出。这是一种数据结构的工作原则&#xff0c;类似于一摞盘子或一叠书本&#xff1a; 最后放进去的元素最先出来 -想象往筒状容器里放盘子&#xff1a; &#xff08;1&#xff09;你放进的最后一个盘子&#xff08…...

RestClient

什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端&#xff0c;它允许HTTP与Elasticsearch 集群通信&#xff0c;而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级&#xff…...

【网络】每天掌握一个Linux命令 - iftop

在Linux系统中&#xff0c;iftop是网络管理的得力助手&#xff0c;能实时监控网络流量、连接情况等&#xff0c;帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

Android Wi-Fi 连接失败日志分析

1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分&#xff1a; 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析&#xff1a; CTR…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误&#xff0c;它们的含义、原因和解决方法都有显著区别。以下是详细对比&#xff1a; 1. HTTP 406 (Not Acceptable) 含义&#xff1a; 客户端请求的内容类型与服务器支持的内容类型不匹…...

如何在看板中有效管理突发紧急任务

在看板中有效管理突发紧急任务需要&#xff1a;设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP&#xff08;Work-in-Progress&#xff09;弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中&#xff0c;设立专门的紧急任务通道尤为重要&#xff0c;这能…...

12.找到字符串中所有字母异位词

&#x1f9e0; 题目解析 题目描述&#xff1a; 给定两个字符串 s 和 p&#xff0c;找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义&#xff1a; 若两个字符串包含的字符种类和出现次数完全相同&#xff0c;顺序无所谓&#xff0c;则互为…...

如何理解 IP 数据报中的 TTL?

目录 前言理解 前言 面试灵魂一问&#xff1a;说说对 IP 数据报中 TTL 的理解&#xff1f;我们都知道&#xff0c;IP 数据报由首部和数据两部分组成&#xff0c;首部又分为两部分&#xff1a;固定部分和可变部分&#xff0c;共占 20 字节&#xff0c;而即将讨论的 TTL 就位于首…...

苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会

在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...

提升移动端网页调试效率:WebDebugX 与常见工具组合实践

在日常移动端开发中&#xff0c;网页调试始终是一个高频但又极具挑战的环节。尤其在面对 iOS 与 Android 的混合技术栈、各种设备差异化行为时&#xff0c;开发者迫切需要一套高效、可靠且跨平台的调试方案。过去&#xff0c;我们或多或少使用过 Chrome DevTools、Remote Debug…...