java静默打印PDF(可实现生产环境下服务器写入PDF模板,然后调用客户端打印机打印)

news2024/11/15 15:43:28

java静默打印PDF可实现生产环境下服务器写入PDF模板,然后调用客户端打印机打印

  • 一、简
      • 需求
      • 实现步骤
  • 二、代码实现
    • 0、打印模板
    • 1、服务器部分 (端口:8090)
      • 1.1、maven依赖
      • 1.2、实体
        • 1.2.1、接口返回类
        • 1.2.2、标签纸页面参数类
        • 1.2.3、PDF模板参数类
      • 1.3、Controller层接口
      • 1.4、写入pdf工具类
      • 1.5、调用客户端jar接口
    • 2、打印机客户端jar (端口:9050)
      • 2.1、依赖
      • 2.2、实体类
        • 2.2.1、纸张对象
        • 2.2.2、统一返回对象
      • 2.3、Controller层,接收服务器调用打印请求
      • 2.4、配置打印参数调用打印机
  • 三、测试
    • 1、调用测试
    • 2、实现结果
    • 3、查看客户端打印机
  • 总结

一、简

需求

写这个的原因主要是因为当时项目中的打印功能是用户打印标签时,每次点击打印是通过把PDF文件下载到客户端浏览器,然后需要通过浏览器去点击打印机实现打印,就非常麻烦,每次都步骤非常复杂,而且每次参数都要重新设置。于是就想着怎么通过java实现自己调用打印机,用户只需要输入需要写入pdf模板的参数,提前配置好打印参数,然后后台自己去调用打印不需要通过浏览器去单个打印。

具体实现把文字、二维码、条形码、图片实现通过模板写入pdf文件,然后再到打印机打印处理

实现步骤

  • 先大致介绍一下这篇文章的内容,主要是通过 Adobe Acrobat DC(或者其他的PDF模板制作app),制作好PDF模板,然后通过itextpdf框架把数据写入到模板对应的文本域中,可以实现PDF文件打开,写入的内容可以正常显示代表pdf文件制作没用问题了。
  • 然后在需要连接打印机打印的上部署一个调用本地打印机的jar包,jar主要通过pdfbox框架实现调用本地打印机,成功把需要打印的pdf文件传递到打印机的打印队列,实现打印。
  • 在打印机主机的jar写好接受服务器打印的pdf的http接口,用于接收服务器传递过来的需要打印的pdf文件以及一些打印参数(包括指定打印机、自定义纸张大小、设置打印参数、以及显示打印对话框等)

二、代码实现

主要包括服务器部分(这里只包括写入pdf模板到调用打印机客户端接口,具体业务根据自己实际业务修改就行)和打印机客户端。

0、打印模板

通过 Adobe Acrobat DC配置对应的文本域,具体配置可以百度查看,这里就不赘述了
在这里插入图片描述

1、服务器部分 (端口:8090)

yml只设置了端口,就不展示出来了

1.1、maven依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
                <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>4.5.15</version>
        </dependency>
<!--pdf生成-->
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.1</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-asian</artifactId>
            <version>5.2.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.pdfbox</groupId>
            <artifactId>pdfbox</artifactId>
            <version>2.0.23</version>
        </dependency>
        <!--fastjson-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.48</version>
        </dependency>

1.2、实体

1.2.1、接口返回类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {
    /**
     * 是否成功
     **/
    private Boolean success;
    /**
     * 错误信息
     **/
    private String message;
    /**
     * 请求状态 200-成功 400-失败
     **/
    private Integer code;
    /**
     * 当前时间戳
     **/
    private Long timestamp;
    /**
     * 返回结果
     **/
    private Object result;

    public static Result ok() {
        return new Result(true, null, 200, System.currentTimeMillis(),null);
    }

    public static Result ok(Object data) {
        return new Result(true, null, 200,System.currentTimeMillis(),data);
    }


    public static Result ok(List<?> data) {
        return new Result(true, null, 200,System.currentTimeMillis(),data);
    }

    public static Result error(String errorMsg) {
        return new Result(false, errorMsg, 400,System.currentTimeMillis(),null);
    }
}

1.2.2、标签纸页面参数类

打印的标签纸页面参数类,添加默认值

/**
 * @author zhengfuping
 * @version 1.0
 * 110*65 的标签纸页面
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PaperVo {
    /**宽*/
    private double width = 100*2.83;
    /**高*/
    private double height = 60*2.83;
    /** X 坐标*/
    private double x = 15;
    /** Y 坐标*/
    private double y = 10;
    /**
     * 打印页面方向:
     *      0:横向 从右向左,1:横向 从左向右,2:纵向。
     * */
    private Integer orientation = PageFormat.PORTRAIT;
    private String name;
}

1.2.3、PDF模板参数类

对应pdf模板的文本域名称

/**
 * @author zhengfuping
 * @version 1.0
 * pdf模板参数
 */
@Data
@Builder
public class Template {
    private String time;

    private String code;

    private String qrCode;

    private String barCode;

    private String image;

    private String age;

    private String name;
}

1.3、Controller层接口

@RequestMapping("/pdf")
@RestController
public class PDFController {
    @Autowired
    private Netty netty;
    @Autowired
    private HttpPdf httpPdf;


    /**
     * @author yingfeng
     * @Param * @param params 包括两个参数 copies:打印张数、duplex:是否打印反面
     * @param request
     * @return * @return Result
     */
    @PostMapping("/print")
    public Result print(@RequestBody Map<String ,Object> params, HttpServletRequest request){
        //因为测试原因,便于理解,所以参数直接添加
        String Code = "43504277201002308221C0100C010145006";
        String barCode = "43504277201002308221C0100C010145006-bar";
        String time = DateUtil.format(new Date(), "yyyyMMdd");
        String qrCode = "https://blog.csdn.net/weixin_52315708";
        String name = "张三";
        String image = "D:/1zheng/dai/excel/exportexcel/a1.jpg";
        Template template = Template.builder()
                .qrCode(qrCode)
                .code(Code)
                .time(time)
                .barCode(barCode)
                .image(image)
                .name(name)
                .age("18").build();
        //转为map是因为需要循环把值写入对应的文本域
        Map<String, Object> map = BeanUtil.beanToMap(template);
		//调用写入文本域工具类,返回对应的byte[]数据
        byte[] pdf = PDFUtil.test(data);
        params.put("pdf",pdf);
        //用于调用客户端的接口
        Result result = httpPdf.doPostWith(params);
        return result;
    }

1.4、写入pdf工具类

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import com.itextpdf.text.pdf.qrcode.EncodeHintType;
import com.itextpdf.text.pdf.qrcode.ErrorCorrectionLevel;
import com.zheng.exceltest.pdf.entity.Template;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import sun.misc.BASE64Encoder;
import java.io.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * @author zhengfuping
 * @version 1.0
 * 实现往打印机打印
 */
@Slf4j
public class PDFUtil {

 public static byte[] test(Map<String, Object> data)  {
        BASE64Encoder encoder = new BASE64Encoder();
        BufferedInputStream bin = null;
        ByteArrayOutputStream bos = null;
        PdfStamper ps = null;
        OutputStream fos = null;
        try {
            // pdf模板
            String fileName = "exportexcel/PDF打印测试模板.pdf";
            //读取pdf
            PdfReader reader  = new PdfReader(fileName);
            bos = new ByteArrayOutputStream();
            //将要生成的目标PDF文件名称
            ps = new PdfStamper(reader, bos);
//        PdfContentByte under = ps.getUnderContent(1);
//        取出报表模板中的所有字段
            AcroFields fields = ps.getAcroFields();

//        对表单数据进行赋值
            fillData(fields,ps,data);
            
            ps.setFormFlattening(true);
            ps.close();
            fos = new FileOutputStream("D:/模板打印测试/a1.pdf");
            fos.write(bos.toByteArray());
            fos.flush();
            fos.close();   //实际应该finally在关闭一次
            bos.close();  //注意,需要在得到 byte[]之前关闭流

//            执行打印
            byte[] bytes = bos.toByteArray();
            return bytes;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 具体往模板的对应文本域写入数据
     * @author zhengfuping
     * @date 2023/8/9 15:55
     * @param fields AcroFields对象
     * @param ps PdfStamper对象
     * @param data 数据
     */
	public static void fillData(AcroFields fields, PdfStamper ps, Map<String, Object> data) throws IOException, DocumentException {
//        设置中文字体
        BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
        ArrayList<BaseFont> fonts = new ArrayList<>();
        Font font = FontFactory.getFont(getFontPath("SimHei.ttf"), BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED,(short)14);
        fonts.add(font.getBaseFont());
        fonts.add(bf);
        fields.setSubstitutionFonts(fonts);
	//循环遍历集合中的文本域字段,根据名称进行不同处理
        for (String key : data.keySet()) {
            System.out.println(key+":"+data.get(key));
            if (data.get(key)==null)continue;
            if (key.equals("image")) {      //      生成图片
                String value = data.get(key).toString();
                String imgpath = value;
                int pageNo = fields.getFieldPositions(key).get(0).page;
                Rectangle signRect = fields.getFieldPositions(key).get(0).position;
                float x = signRect.getLeft();
                float y = signRect.getBottom();
                // 根据路径读取图片
                Image image = Image.getInstance(imgpath);
                // 获取图片页面
                PdfContentByte under = ps.getOverContent(pageNo);
                // 图片大小自适应
                image.scaleToFit(signRect.getWidth(), signRect.getHeight());
                // 添加图片
                image.setAbsolutePosition(x, y);
                under.addImage(image);
            } else if (key.equals("barCode")) {     //生成条形码
                //遍历条码字段
                String value = data.get(key).toString();
//              获取位置(左上右下)
                AcroFields.FieldPosition fieldPosition = fields.getFieldPositions(key).get(0);
//                  ?null
                PdfNumber rNum = fields.getFieldItem(key).getWidget(0).getAsDict(PdfName.AP).getAsNumber(PdfName.R);
                if (rNum == null) {
                    fieldPosition.position.setRotation(0);
                } else {
                    fieldPosition.position.setRotation(rNum.intValue());
                }
                //绘制条码
                Barcode128 barcode128 = new Barcode128();
                barcode128.setSize(8);
                if (fieldPosition.position.getRotation() == 90 || fieldPosition.position.getRotation() == 270) {
                    barcode128.setBarHeight(25);
                    barcode128.setX(0.82f);
                } else {
                    //条码宽高
//                    barcode128.setBarHeight(fieldPosition.position.getHeight() - 40);
//                    barcode128.setX(fieldPosition.position.getWidth() / 150);
                    barcode128.setBarHeight(25);
                    barcode128.setX(0.5f);
                }
                //条码与数字间距
                barcode128.setBaseline(8);
                //条码值
                barcode128.setCode(value);
                barcode128.setStartStopText(false);
                barcode128.setExtended(true);
                //绘制在第一页
                PdfContentByte cb = ps.getOverContent(1);
                //生成条码图片
                Image image128 = barcode128.createImageWithBarcode(cb, null, null);
                //旋转度数
                image128.setRotationDegrees(fieldPosition.position.getRotation());

                //左边距(居中处理)
                float marginLeft = (fieldPosition.position.getRight() - fieldPosition.position.getLeft() - image128.getWidth()) / 2;
                //条码位置
                image128.setAbsolutePosition(fieldPosition.position.getLeft() + marginLeft, fieldPosition.position.getBottom());
                //加入条码
                cb.addImage(image128);
            }else if ("qrCode".equals(key)){        //生成二维码
                //           遍历二维码字段
                String value = data.get(key).toString();
                // 获取属性的类型
                if (value != null ) {
                    //获取位置(左上右下)
                    AcroFields.FieldPosition fieldPosition = fields.getFieldPositions(key).get(0);
                    //绘制二维码
                    float width = fieldPosition.position.getRight()/2 - fieldPosition.position.getLeft()/2;
                    //设定容错性二维码容错率用字母表示,容错能力等级分为:L、M、Q、H四级:L :7%;M:15%;Q:25%;H:30%
                    Map<EncodeHintType, Object> hints = new HashMap<>();
                    hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
                    BarcodeQRCode pdf417 = new BarcodeQRCode(value.toString(), (int) width, (int) width, hints);
                    //生成二维码图像
                    Image image128 = pdf417.getImage();
                    //绘制在第一页
                    PdfContentByte cb = ps.getOverContent(1);
                    //左边距(居中处理)
                    float marginLeft = (fieldPosition.position.getRight() - fieldPosition.position.getLeft() - image128.getWidth()) / 2;
                    //条码位置
                    image128.setAbsolutePosition(fieldPosition.position.getLeft() + marginLeft, fieldPosition.position.getBottom()-3f);
                    //加入条码
                    cb.addImage(image128);
                }
            }else{          //生成文字
                String value = data.get(key).toString();
//                String partCode = (String) data.get("name");
                设置文本大小
//                if (partCode.length()<8 && key.equals("age")){
//                    fields.setFieldProperty(key,"textsize",(float)36,null);
//
//                }else {
//                    fields.setFieldProperty(key,"textsize",(float)9,null);
//                }
//                设置文本字体
                if (Pattern.compile("[\u4E00-\u9FA5]").matcher(key).find()){
                    fields.setFieldProperty(key,"textfont",bf,null);    //中文
                    fields.setField(key, value);
                }else {
                    fields.setFieldProperty(key,"textfont",font.getBaseFont(),null);  //英文
                    fields.setField(key, value);
                }
            }
        }
    }

    /**
     * 获取本机的字体文件
     *
     * @param fontName
     */
    private static String getFontPath(String fontName) {
        String fontPath = "C:\\Windows\\Fonts\\" + fontName;
        // 判断系统类型,加载字体文件
        java.util.Properties prop = System.getProperties();
        String osName = prop.getProperty("os.name").toLowerCase();
        if (osName.indexOf("linux") > -1) {
            fontPath = "/usr/share/fonts/" + fontName;
        }
        log.info(osName + "-------------------" + fontPath);
        return fontPath;
    }

1.5、调用客户端jar接口

/**
 * @author zhengfuping
 * @version 1.0
 * 调用客户端打印机的jar
 * @date 2023/4/14 14:35
 */
@Service
public class HttpPdf {
    @Autowired
    private RestTemplate restTemplate;

	//接口路径
    final String url = "http://127.0.0.1:9050/print/print";


    public Result doPostWith(Map<String ,Object> params){
        PaperVo paperVo = new PaperVo();
        System.out.println();
        params.put("paper",paperVo);
        Result result = restTemplate.postForObject(url, params, Result.class);
        return result;
    }

2、打印机客户端jar (端口:9050)

2.1、依赖

 <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.apache.pdfbox</groupId>
            <artifactId>pdfbox</artifactId>
            <version>2.0.23</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.4.0</version>
        </dependency>
    </dependencies>

2.2、实体类

同上

2.2.1、纸张对象

@Data
public class PaperVo {
    /**长*/
    private double width = 216;
    /**宽*/
    private double height = 360;
    /** X 坐标*/
    private double x = 5;
    /** Y 坐标*/
    private double y = 100;
    /**
     * 打印页面方向:
     *      0:横向 从右向左,1:横向 从左向右,2:纵向。
     * */
    private Integer orientation = PageFormat.PORTRAIT;
}

2.2.2、统一返回对象

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {
    /**
     * 是否成功
     **/
    private Boolean success;
    /**
     * 错误信息
     **/
    private String message;
    /**
     * 请求状态 200-成功 400-失败
     **/
    private Integer code;
    /**
     * 当前时间戳
     **/
    private Long timestamp;
    /**
     * 返回结果
     **/
    private Object result;

    public static Result ok() {
        return new Result(true, null, 200, System.currentTimeMillis(),null);
    }

    public static Result ok(Object data) {
        return new Result(true, null, 200,System.currentTimeMillis(),data);
    }


    public static Result ok(List<?> data) {
        return new Result(true, null, 200,System.currentTimeMillis(),data);
    }

    public static Result error(String errorMsg) {
        return new Result(false, errorMsg, 400,System.currentTimeMillis(),null);
    }
}

2.3、Controller层,接收服务器调用打印请求

/**
 * @author zhengfuping
 * @version 1.0
 * 接收调用打印请求
 */
@RequestMapping("/print")
@RestController
public class PrintController {
    /**
     * @Description: 默认使用打印机的名称。可以存在数据库里做持久化
     */
    private static String printName = "SATO CL4NX Plus 305dpi";


    /**
     * @Description: 获取打印机列表
     * @Param: []
     * @Return: com.wq.print.util.R
     */
    @RequestMapping("/list")
    public Result list() {
        ArrayList<String> list = new ArrayList<>();
        // 遍历所有打印机的名称
        for (PrintService ps : PrinterJob.lookupPrintServices()) {
            list.add(ps.getName());
        }
        if (list.size() != 0) {
            return Result.ok(list);
        }
        return Result.error("暂无可用打印机,请检查系统打印机设置");
    }
    /**
     * @Description: 设置使用的打印机
     * @Param:
     * @Return: com.wq.print.util.R
     */
    @PostMapping("/setPrint")
    public Result setPrint(@RequestParam("printName") String printName) {
        PrintController.printName = printName;
        return Result.ok("打印机设置成功");
    }

    @PostMapping("/print")
    public Result print(@RequestBody Map<String ,Object> params, HttpServletRequest request){
        try {
            String pdfBase64Str = String.valueOf(params.get("pdf"));
            if (StrUtil.isEmptyIfStr(pdfBase64Str)) {
                return Result.error("pdf的Base64字符串有误或为空,请检查");
            }
            //因为传输过程中会把 byte[]转为 pdfBase64Str,需要重新转回来
            byte[] pdfByte = PrintUtil.base64ToFileByte(pdfBase64Str);
				//设置参数,没设置也要给默认值
            int copies = params.get("copies") == null ?1 : Integer.parseInt(params.get("copies").toString());
            boolean duplex = params.get("duplex") != null && Boolean.parseBoolean(params.get("duplex").toString());
            Map<String,Object> pdf = (Map<String,Object>) params.get("paper");
            PaperVo paperVo = null;
            //如果服务器没有传对应参数,就用这边的
            if (pdf==null){
                paperVo = new PaperVo();
            }else {
                paperVo = BeanUtil.mapToBean(pdf, PaperVo.class, false, new CopyOptions());
            }
            Boolean print = PrintUtil.print(pdfByte, PrintController.printName, copies, duplex,paperVo);

            if (print){
                return Result.ok("打印完成");
            }else {
                return Result.ok("打印失败");
            }
        } catch (NumberFormatException e) {
            e.printStackTrace();
            return Result.ok("打印失败"+e.getMessage());
        }
    }
}

2.4、配置打印参数调用打印机

配置配置参数调用客户端打印机

public class PrintUtil {

    /** 
     * 调用配置打印机
     * @author zhengfuping
     * @param pdfByte 数据
     * @param printName  打印机名称
     * @param copies 打印张数
     * @param duplex 是否打印反面
     * @param paperVo 纸张参数
     * @return Boolean 
     */
    public static Boolean print(byte[] pdfByte, String printName, int copies, boolean duplex , PaperVo paperVo) {
        //加载pdf文件对象
        try(PDDocument document = PDDocument.load(pdfByte)){
            //            创建打印任务
            PrinterJob job = PrinterJob.getPrinterJob();
            //            遍历所有打印机的名称
            for (PrintService ps : PrinterJob.lookupPrintServices()){
                String psName = ps.getName();
                if (psName.equals(printName)){
                    job.setPrintService(ps);
                    break;
                }
            }

            job.setPageable(new PDFPageable(document));
//            纸张对象
            Paper paper = new Paper();
            // 设置打印纸张大小
            paper.setSize(paperVo.getWidth(),paperVo.getHeight());
            // 设置打印位置 坐标
            paper.setImageableArea(paperVo.getX(),paperVo.getY(),paper.getWidth(),paper.getHeight());

//            打印的页面参数
            PageFormat pageFormat = new PageFormat();
            pageFormat.setPaper(paper);
            pageFormat.setOrientation(paperVo.getOrientation()); //横向 从右向左

            Book book = new Book();
            //            打印页面对象--配置
            PDFPrintable pdfPrintable = new PDFPrintable(document, Scaling.SHRINK_TO_FIT, true, 0, true);
            book.append(pdfPrintable,pageFormat,1);
            job.setPageable(book);
//            打印份额
            job.setCopies(copies);

            if (duplex){
                HashPrintRequestAttributeSet printSet = new HashPrintRequestAttributeSet();
                printSet.add(Sides.DUPLEX);
                job.print(printSet);
            }else {
                job.print();
            }
            document.close();
            return true;

        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    /** 
     * Base64转换编码
     * @Param * @param strBase64
     */
    
    public static byte[] base64ToFileByte(String strBase64) {
        return java.util.Base64.getDecoder().decode(strBase64);
    }

三、测试

1、调用测试

使用postman调用服务器的打印接口
在这里插入图片描述

最终实现的打印文件因为测试我是直接写入到本地的,实际项目中可能是通过浏览器调用,需要上载到浏览器,直接配置request就行,如果文件可以正常打开,并且客户端有接收到参数,pdf中有数据,说明服务器端代码没问题了。

在这里插入图片描述

  • 具体打印的pdf文件
    在这里插入图片描述

2、实现结果

具体直接最后一句document.close(); 调用打印机后,对应的打印队列中有任务,则说明实现成功
在这里插入图片描述

3、查看客户端打印机

在这里插入图片描述

总结

  • 具体实现上需要注意文本域的名称要对应上;

  • 局限是需要再客户端服务器需要在同一个局域网,如果不是的话,则客户端的接口也需要映射出去用于给服务器调用。

  • 客户端的代码实际上可以转为jar后通过 exe4j 转为.exe文件,再通过Inno Setup 把jdk绑定进去。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/853682.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【EI/SCOPUS检索】第四届应用力学与机械工程国际学术会议(ICAMME 2023)

第四届应用力学与机械工程国际学术会议&#xff08;ICAMME 2023&#xff09; 2023 4th International Conference on Applied Mechanics and Mechanical Engineering (ICAMME 2023) 第四届应用力学与机械工程国际学术会议&#xff08;ICAMME 2023&#xff09;将于2023年11月10…

期刊和会议缩写查询网站

1.https://pubmed.ncbi.nlm.nih.gov/?termMedicalImageComputingandComputer-AssistedIntervention 2. http://www.letpub.com.cn/index.php?pagejournalapp&viewsearch 3. https://blog.csdn.net/weixin_44557349/article/details/120825927 https://blog.csdn.net/ret…

Kafka:安装和配置

producer&#xff1a;发布消息的对象&#xff0c;称为消息产生者 &#xff08;Kafka topic producer&#xff09; topic&#xff1a;Kafka将消息分门别类&#xff0c;每一个消息称为一个主题&#xff08;topic&#xff09; consumer&#xff1a;订阅消息并处理发布消息的对象…

【solon生态】- solon.cloud.micrometer插件使用指南及micrometer详解

solon.cloud.micrometer插件使用指南 solon是什么solon的cloud生态图快速入门 micrometer指南micrometer是什么监控系统 Supported Monitoring Systems注册表 Registry度量 Meters度量名 Naming Meters度量标签 Tag Naming通用标签 Common Tags 指标过滤器 MeterFilter聚合速率…

LeetCode_01 精度丢失

1281. 整数的各位积和之差 给你一个整数 n&#xff0c;请你帮忙计算并返回该整数「各位数字之积」与「各位数字之和」的差。 示例 输入&#xff1a;n 234 输出&#xff1a;15 解释&#xff1a; 各位数之积 2 * 3 * 4 24 各位数之和 2 3 4 9 结果 24 - 9 15示例 …

vue中使用this.$refs获取不到子组件的方法,属性方法都为undefined的解决方法

问题描述 vue2中refs获取不到子组件中的方法&#xff1f;&#xff0c;而获取到的是undefined 原因及解决方案&#xff1a; 第一种、在循环中注册了很多个ref 因为注册了多个ref&#xff0c;获取是不能单单知识refs.xxx&#xff0c;需要使用数组和索引来获取具体一个组件refs[…

限流式保护器在高校宿舍电气防火的应用

安科瑞 华楠 引言 14日早晨6时10分左右&#xff0c;上海商学院徐汇校区学生宿舍楼发生火灾&#xff0c;4名女生从六楼宿合阳台跳下逃生当场死亡&#xff0c;酿成近年来惨烈的校园事故。宿舍火灾初步判断缘起于寝室里使用热得快导致电器故障并将周围可燃物引燃。 任何条生命都是…

【方法】7Z压缩包如何解压?

你知道7Z压缩包如何解压吗&#xff1f; 7Z是一种主流高效的压缩格式&#xff0c;它可以用多种压缩解压软件来解压&#xff0c;像7-Zip、WinRAR等常用的解压缩软件都可以解压7Z压缩包。 首先我们可以从官网或者软件商店里免费下载7-Zip或者WinRAR解压缩软件&#xff0c;再安装…

PXE-kickstart无人值守安装操作系统

PXE的概念&#xff1a; PXE&#xff08;Pre-boot Execution Environment&#xff0c;预启动执行环境&#xff09;是由Intel公司开发的最新技术&#xff0c;工作于C/S的网络模式&#xff0c;支持工作站通过网络从远端服务器下载映像&#xff0c;并由此支持通过网络启动操作系统…

leetcode 2616. 最小化数对的最大差值

在数组nums中找到p个数对&#xff0c;使差值绝对值的和最小。 思路&#xff1a; 最小差值应该是数值相近的一对数之间产生&#xff0c;让数值相近的数字尽量靠在一起方便计算&#xff0c;所以需要排序。 这里不去直接考虑一对对的数字&#xff0c;而是直接考虑差值的取值。 …

msvcp120.dll丢失的解决方法,哪种解决方法更实用

msvcp120.dll是Microsoft Visual C 2013库中的一个动态链接库文件。它包含了在使用Visual C 2013编译的应用程序中所需的函数和资源。这个文件通常用于在Windows操作系统上运行使用Visual C 2013编写的软件。如果缺少或损坏了msvcp120.dll文件&#xff0c;可能会导致相关软件无…

Wav2Lip实践

1. 安装 1.1 安装 conda以指定python版本运行环境 下载&#xff1a;Index of /https://repo.anaconda.com/archive/index.html 1.2 如按旧项目基于python3.6版本对话&#xff0c;会有很多包找不到的情况&#xff0c;经摸索后以python3.9构建成功&#xff0c; conda instal…

js代码加密,也能在vs code中进行?

在vs code中对js代码混淆加密 Vs code是常用的js代码编辑工具。本文演示如何在vs code中调用jshaman扩展&#xff0c;实现非常方便的js代码加密。 打开vs code&#xff1a; 点击左侧的“扩展”&#xff0c;打开后搜索“jshaman”。 &#xff08;JShaman是业界很有名的JS代码…

Stable Diffusion - 底部视角 (From Below) 拍摄的图像 LoRA 与配置

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/132192139 图像来源自 哥特风格 与 底部视角 的结合&#xff0c;更具有视觉冲击力。 从下面或底部 (From Below) 拍摄人物&#xff0c;可以创造出…

学C语言 | 位运算符<<的高级用法

前言 在上一篇文章中&#xff0c;我们介绍了~运算符的高级用法&#xff0c;本篇文章&#xff0c;我们将介绍<< 运算符的一些高级用法。 一、人物简介 第一位闪亮登场&#xff0c;有请今后会一直教我们C语言的老师 —— 自在。 第二位上场的是和我们一起学习的小白程序猿…

流量分析日志查看

一流量分析 buuctf wireshark 从题目出发&#xff0c;既然是上传登录信息&#xff0c;就直接过滤post请求&#xff0c;即搜索 http.request.methodPOST&#xff0c;因为上传用户登录信息使用的一定是http里的post方法 模式过滤 http.request.method “GET” http.request.…

数据要素市场之破四化建四化,拆墙又砌墙

摘要&#xff1a;8月8日&#xff0c;首届贵州科技节“2023数据要素流通关键技术论坛”在贵阳举行。此次论坛由贵州省科学技术协会指导&#xff0c;贵州省计算机学会主办&#xff0c;中国计算机学会贵阳会员活动中心、贵州轻工职业技术学院、贵州电子科技职业学院、贵州省大数据…

基于kubeadm部署K8S集群

目录 基于kubeadm部署K8S集群 一、环境准备 1、主机初始化配置 2、配置主机名并绑定hosts&#xff0c;不同主机名称不同 3、主机配置初始化 二、部署docker环境 1、三台主机上分别部署 Docker 环境 2、镜像加速器&#xff08;所有主机配置&#xff09; 三、部署kubern…

模拟实现消息队列

目录 1. 需求分析1.1 介绍一些核心概念核心概念1核心概念2 1.2 消息队列服务器&#xff08;Broker Server&#xff09;要提供的核心 API1.3 交换机类型1.3.1 类型介绍1.3.2 转发规则&#xff1a; 1.4 持久化1.5 关于网络通信1.5.1 客户端与服务器提供的对应方法1.5.2 客户端额外…

Android APK体积优化(瘦身)

1、基础知识&#xff1a; 1.1 apk结构 lib &#xff1a;存放so文件&#xff0c;对应不同的cpu架构 res &#xff1a;资源文件&#xff0c;layout、drawable等&#xff0c;经过aapt编译 assets &#xff1a;资源文件&#xff0c;不经过aapt编译 classes.dex &#xff1a;dx编译…