java图片压缩

news2024/11/17 16:46:03

1背景

查看各种文章,发现thumbnailator的压缩率和压缩效果都不错,thumbnailator又是使用java实现的,所以直接扒源码,找到了里面实现压缩的关键代码,封装成一个压缩工具类,有需要的同学可以参考。thumbnailator里面有用到很多不错的设计模式,后期也会开相应的模块来介绍。

2 使用方法

2.1 如需要解析jpeg图片颜色模式为CMYK的图片,需要导入依赖

com.twelvemonkeys.imageio imageio-jpeg 3.6

2.1 工具类使用

1.将目录图片下的所有能压缩的图片使用中等质量压缩到目录图片3,文件名保持不变,输出格式为jpg

String source = "E:\\图片压缩\\图片";
String traget = "E:\\图片压缩\\图片3";
// 压缩图片目录下的所有
ThumbnailUtil.of(new File(source).listFiles(ThumbnailUtil.readFilter())).identifyCompress(ThumbnailUtil.ratios[1])
        .outputFormat("jpg").toFiles(new File(traget), null);

2.将目录图片下的所有能压缩的图片使用尺寸不变,质量压缩50%压缩到目录图片3,文件名和格式使用原有输入的文件名和格式输出

String source = "E:\\图片压缩\\图片";
String traget = "E:\\\图片压缩\\图片3";		
ThumbnailUtil.of(new File(source).listFiles(ThumbnailUtil.readFilter())).scale(1D).outputQuality(0.5D)
        .outputFormat(ThumbnailUtil.orgForm).toFiles(new File(traget), "");

3.将图片目录下的原图.jpg使用中等质量压缩到目录图片3,文件名和格式使用原有输入的文件名和格式输出

String source = "E:\\图片压缩\\图片\\原图.jpg";
String traget = "E:\\图片压缩\\图片3\\原图.jpg";
// 压缩图片目录下的所有
ThumbnailUtil.of(new File(source)).identifyCompress(ThumbnailUtil.ratios[1])
        .toFile(new File(traget));	

4.将图片目录下的原图.jpg使用尺寸不压缩,质量压缩到到目标图片40%质量,文件名和格式使用输入的文件名和格式输出

String source = "E:\\图片压缩\\图片\\原图.jpg";
String traget = "E:\\图片压缩\\图片3\\原图.jpg";				
ThumbnailUtil.of(new File(source)).scale(1D).outputQuality(0.4D)

5.将MultipartFile格式的多张图片进行压缩,使用最高质量压缩(尺寸不变,图片质量为原来的0.8)到目录图片3,文件名和格式使用原有输入的文件名和格式输出MultipartFile格式文件(使用该方法最好使用MimetypesFileTypeMap识别一下多个图片格式是否全部为图片,只压缩图片)

MultipartFile[] myFiles = ThumbnailUtil.of(myFiles)
                .identifyCompress(ThumbnailUtil.ratios[0])
                .outputFormat(ThumbnailUtil.orgForm).asMultipartFiles();

2.2 压缩效果

原图尺寸3840*2400,图片大小1311KB:
在这里插入图片描述

压缩比率identifyCompress选low低压缩率,尺寸3840*2400,图片大小1025KB
在这里插入图片描述

压缩比率identifyCompress选medium中等压缩率,尺寸3072*1920,图片大小491KB
在这里插入图片描述

压缩比率identifyCompress选high高压缩率,尺寸2688*1680,图片大小317KB
在这里插入图片描述

2.2 压缩工具类

import org.apache.commons.lang3.StringUtils;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;

import javax.activation.MimetypesFileTypeMap;
import javax.imageio.*;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.List;
import java.util.*;
import java.util.stream.StreamSupport;


public class ThumbnailUtil {

    // 压缩比率, 低(原质量*0.85),中(原质量*0.7),高(原质量*0.6)
    public static String[] ratios = new String[]{"low", "medium", "high"};
    // 原始格式
    public static String orgForm = "orgForm";

    public static Builder<File> of(File... files) {
        Iterable<File> iter = Arrays.asList(files);
        return new Builder<>(iter);
    }

    public static Builder<BufferedImage> of(BufferedImage... images) {
        return new Builder<>(Arrays.asList(images));
    }

    public static Builder<InputStream> of(InputStream... inputStreams) {
        return new Builder<>(Arrays.asList(inputStreams));
    }

    public static Builder<MultipartFile> of(MultipartFile... multipartFiles) {
        return new Builder<>(Arrays.asList(multipartFiles));
    }

    public static FilenameFilter readFilter() {
        String readFormats[] = ImageIO.getReaderFormatNames();
        Set<String> readFormatSet = new HashSet<>(Arrays.asList(readFormats));
        String writeFormats[] = ImageIO.getWriterFormatNames();
        return new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                String seprator = ".";
                if (name == null || !name.contains(seprator)) {
                    return false;
                }
                String format = name.substring(name.lastIndexOf(seprator) + 1);
                return readFormatSet.contains(format);
            }
        };
    }

    public static class Builder<T> {
        // 待转换源数据
        private final Iterable<T> sources;
        // 输出格式
        private String outputFormat = null;
        //        // 原图宽
//        private int width = -1;
//        // 原图高
//        private int height = -1;
        // 压缩比率
        private String compressionRatio = null;

        // 缩放后宽
        private double scaleWidth = Double.NaN;
        // 缩放后高
        private double scaleHeight = Double.NaN;
        // 压缩质量系数 0-1之间
        private double outputQuality = Double.NaN;

        private Builder() {
            sources = null;
        }

        private Builder(Iterable<T> sources) {
            this.sources = sources;
        }

        public Builder<T> identifyCompress(String compressionRatio) {
            if (!Objects.equals(Double.NaN, scaleWidth)
                    || !Objects.equals(Double.NaN, scaleHeight)
                    || !Objects.equals(Double.NaN, outputQuality)
            ) {
                // 有设置scale和outputQuality则不使用自动压缩选项
                return this;
            } else if (null == compressionRatio) {
                this.compressionRatio = ratios[1];
                return this;
            }
            if (!Arrays.toString(ratios).contains(compressionRatio)) {
                throw new IllegalArgumentException("Unsupported compressionRatio Type.");
            }
            this.compressionRatio = compressionRatio;
            return this;
        }

        private Builder<T> identifyCompress(String compressionRatio, int width, int height) {
            if (width <= 0 || height <= 0) {
                throw new IllegalArgumentException("Width (" + width + ") and height (" + height + ") cannot be <= 0");
            }
            // 为了支持多线程压缩, 需要将可变变量直接传入方法中,不能使用共享变量返回scaleWidth和outputQuality
            if (!Objects.equals(Double.NaN, scaleWidth)
                    || !Objects.equals(Double.NaN, scaleHeight)
                    || !Objects.equals(Double.NaN, outputQuality)
            ) {
                // 有设置scale和outputQuality则不使用自动压缩选项
                return this;
            } else if (null == compressionRatio) {
                compressionRatio = ratios[1];
            }
            if (!Arrays.toString(ratios).contains(compressionRatio)) {
                throw new IllegalArgumentException("Unsupported compressionRatio Type.");
            }
            int min = width < height ? width : height;
            double offset;
            Builder builder = new Builder();
            if (Objects.equals(ratios[0], compressionRatio)) {
                // 最低压缩,图片保持原来尺寸,质量为原来的0.8
                builder.scaleWidth = builder.scaleHeight = 1.0D;
                builder.outputQuality = 0.8D;
                return builder;
            } else if (Objects.equals(ratios[1], compressionRatio)) {
                offset = 0.4D;
            } else {
                offset = 0.3D;
            }
            if (min <= 1024) {
                // 最小像素小于1024,长和宽不压缩
                builder.scaleWidth = builder.scaleHeight = 1.0D;
                builder.outputQuality = (builder.outputQuality = 0.3D + offset) <= 1 ? builder.outputQuality : 1;
            } else if (min > 1024 && min <= 3 * 1024) {
                builder.scaleHeight = (builder.scaleHeight = 0.4D + offset) <= 1 ? builder.scaleHeight : 1;
                builder.scaleWidth = builder.scaleHeight;
                builder.outputQuality = (builder.outputQuality = 0.3D + offset) <= 1 ? builder.outputQuality : 1;
            } else {
                builder.scaleHeight = (builder.scaleHeight = 2048D / min + offset) <= 1 ? builder.scaleHeight : 1;
                builder.scaleWidth = builder.scaleHeight;
                builder.outputQuality = builder.scaleHeight;
            }
            return builder;
        }

        public Builder<T> scale(double scaleWidth, double scaleHeight) {
            if (scaleWidth <= 0.0 || scaleHeight <= 0.0) {
                throw new IllegalArgumentException(
                        "The scaling factor is equal to or less than 0."
                );
            }
            if (Double.isNaN(scaleWidth) || Double.isNaN(scaleHeight)) {
                throw new IllegalArgumentException(
                        "The scaling factor is not a number."
                );
            }
            if (Double.isInfinite(scaleWidth) || Double.isInfinite(scaleHeight)) {
                throw new IllegalArgumentException(
                        "The scaling factor cannot be infinity."
                );
            }
            this.scaleWidth = scaleWidth;
            this.scaleHeight = scaleHeight;
            return this;
        }

        public Builder<T> scale(double scale) {
            return scale(scale, scale);
        }

        public Builder<T> outputQuality(double quality) {
            if (quality < 0.0f || quality > 1.0f) {
                throw new IllegalArgumentException(
                        "The quality setting must be in the range 0.0f and " +
                                "1.0f, inclusive."
                );
            }
            outputQuality = quality;
            return this;
        }

        public Builder<T> outputFormat(String formatName) {
            if (StringUtils.isEmpty(formatName)) {
                this.outputFormat = orgForm;
                return this;
            } else if (Objects.equals(orgForm, formatName)) {
                this.outputFormat = formatName;
                return this;
            }
            Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(formatName);
            if (!writers.hasNext()) {
                throw new UnsupportedOperationException(
                        "No suitable ImageWriter found for " + formatName + "."
                );
            }
            this.outputFormat = formatName;
            return this;
        }

        private String outputFormat(T source, String formatName) throws IOException {
            if (source == null) {
                throw new IllegalArgumentException("The resource being processed is null.");
            }
            if (StringUtils.isEmpty(formatName)) {
                formatName = orgForm;
            } else if (!Objects.equals(orgForm, formatName)) {
                return formatName;
            }
            Iterator<ImageReader> iterReader = ImageIO.getImageReaders(ImageIO.createImageInputStream(source));
            if (null == iterReader || !iterReader.hasNext()) {
                throw new UnsupportedOperationException("The resource being processed is not a picture.");
            }
            formatName = iterReader.next().getFormatName();
            Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(formatName);
            if (!writers.hasNext()) {
                throw new UnsupportedOperationException(
                        "No suitable ImageWriter found for " + formatName + "."
                );
            }
            return formatName;
        }

        private void write(T source, final ImageOutputStream outputStream) throws IOException {
            if (StringUtils.isEmpty(outputFormat)) {
                throw new IllegalStateException("Output format has not been set.");
            }
            Objects.requireNonNull(outputStream, "Could not open OutputStream.");
            BufferedImage srcImage;
            if (source instanceof BufferedImage) {
                srcImage = (BufferedImage) source;
            } else if (source instanceof File) {
                srcImage = ImageIO.read((File) source);
            } else if (source instanceof MultipartFile) {
                srcImage = ImageIO.read(((MultipartFile) source).getInputStream());
                // 将MultipartFile装换为InputStream
                source = (T) ((MultipartFile) source).getInputStream();
            } else if (source instanceof InputStream) {
                srcImage = ImageIO.read((InputStream) source);
            } else {
                throw new IllegalArgumentException("Unsupported ImageIO Type.");
            }
            String outputFormatName = this.outputFormat(source, outputFormat);
            System.out.println("outputFormatName : " + outputFormatName);
            // 原图宽
            int width = srcImage.getWidth();
            // 原图高
            int height = srcImage.getHeight();
            // 如果没有设置宽高和压缩比,则自动识别最佳压缩比
            Builder builder = this.identifyCompress(compressionRatio, width, height);
            double scaleWidth = builder.scaleWidth;
            double scaleHeight = builder.scaleHeight;
            double outputQuality = builder.outputQuality;
            System.out.println("scaleWidth ; " + scaleWidth + " scaleHeight : " + scaleHeight + " outputQuality : " + outputQuality);
            if (Objects.equals(outputQuality, Double.NaN)) {
                throw new IllegalArgumentException("outputQuality is null.");
            }
            // 缩放后宽
            int sclWidth = Objects.equals(Double.NaN, scaleWidth) ? width : (int) (width * scaleWidth);
            // 缩放后高
            int sclHeight = Objects.equals(Double.NaN, scaleHeight) ? height : (int) (height * scaleHeight);
            System.out.println("sclWidth : " + sclWidth + " sclHeight : " + sclHeight);
//            Image from = srcImage.getScaledInstance(width, height, Image.SCALE_AREA_AVERAGING);
            // 输出BufferedImage流
            long startTime = System.currentTimeMillis();
            BufferedImage destImage =
                    new BufferedImage(sclWidth, sclHeight, BufferedImage.TYPE_INT_RGB);
            Graphics2D g = destImage.createGraphics();
            // 消除锯齿
            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
//            g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,RenderingHints.VALUE_STROKE_DEFAULT);
            g.addRenderingHints(new HashMap<>());
            g.drawImage(srcImage, 0, 0, sclWidth, sclHeight, null);
            System.out.println("image scale cost time : " + (System.currentTimeMillis() - startTime));
            // 压缩后增加一点点锐化,如不需要的,以下4行代码可以干掉
            // 拉普拉斯边缘锐化
//            startTime = System.currentTimeMillis();
//            BufferedImage imageSharpen = ImageSharpen.lapLaceSharpDeal(destImage);
//            System.out.println("lapLaceSharpDeal cost time : " + (System.currentTimeMillis() - startTime));
//            //设置为透明覆盖
//            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.2f));
//            //在背景图片上添加锐化的边缘
//            g.drawImage(imageSharpen, 0, 0, imageSharpen.getWidth(), imageSharpen.getHeight(), null);
//            // 释放对象 透明度设置结束
//            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));

            g.dispose();
            ImageWriter writer = null;
            ImageTypeSpecifier type =
                    ImageTypeSpecifier.createFromRenderedImage(destImage);
            // formatName不生效, 所以统一使用jpg
//            Iterator iterIO = ImageIO.getImageWriters(type, outputFormatName);
            Iterator iterIO = ImageIO.getImageWriters(type, "jpg");
            if (iterIO.hasNext()) {
                writer = (ImageWriter) iterIO.next();
            }
            if (writer == null) {
                throw new IllegalArgumentException("ImageWriter is null.");
            }

            IIOImage iioImage = new IIOImage(destImage, null, null);
            ImageWriteParam param = writer.getDefaultWriteParam();
            if (param.canWriteCompressed() && !outputFormatName.equalsIgnoreCase("bmp")) {
                param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
                param.setCompressionQuality((float) outputQuality);    //这里可以指定压缩的程度 0-1.0
            } else {
//                param.setCompressionQuality(0.0f);
                System.out.println("The outputFormat (" + outputFormatName + ") cannot be compressed");
            }

//            ImageOutputStream outputStream = ImageIO.createImageOutputStream(os);

//            if (outputStream == null) {
//                throw new IOException("Could not open OutputStream.");
//            }
            writer.setOutput(outputStream);
            writer.write(null, iioImage, param);
            writer.dispose();
            outputStream.close();
        }

        public ByteArrayInputStream asByteArray() throws IOException {
            Iterator<T> iter = sources.iterator();
            T source = iter.next();
            if (iter.hasNext()) {
                throw new IllegalArgumentException("Cannot create one thumbnail from multiple original images.");
            }
            // 将缓存中的图片按照指定的配置输出到字节数组中
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            write(source, ImageIO.createImageOutputStream(byteArrayOutputStream));
            // 从字节数组中读取图片
            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
//            InputStream inputStream = new ByteArrayInputStream(byteArrayInputStream);
//            MultipartFile file = new MockMultipartFile(ContentType.APPLICATION_OCTET_STREAM.toString(), byteArrayInputStream);
            return byteArrayInputStream;
        }

        public MultipartFile[] asMultipartFiles() {
            long startTime = System.currentTimeMillis();
            MultipartFile[] multipartFiles = StreamSupport.stream(sources.spliterator(), true).map(source -> {
                if (!(source instanceof File)
                        && (!(source instanceof MultipartFile))
                ) {
                    throw new IllegalStateException("Cannot create thumbnails to files if original images are not from files or multipartFile.");
                }
                String filename = "";
                String mimeType = "";
                if (source instanceof File) {
                    filename = ((File) source).getName();
                    MimetypesFileTypeMap fileTypeMap = new MimetypesFileTypeMap();
                    mimeType = fileTypeMap.getContentType(filename);
                } else if (source instanceof MultipartFile) {
                    filename = ((MultipartFile) source).getOriginalFilename();
                    mimeType = ((MultipartFile) source).getContentType();
                }
                // 将缓存中的图片按照指定的配置输出到字节数组中
                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                try {
                    System.out.println("Process the image " + filename + " start.");
                    write(source, ImageIO.createImageOutputStream(byteArrayOutputStream));
                } catch (IOException e) {
                    String desc = "Failed to process the image " + filename + " .";
                    System.out.println(desc);
                    throw new IllegalArgumentException(desc, e);
                }
                // 从字节数组中读取图片
                ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
                String octetStream = "application/octet-stream";
                MultipartFile multipartFile = null;
                try {
                    multipartFile =  new MockMultipartFile(octetStream, filename, mimeType, byteArrayInputStream);
                } catch (IOException e) {
                    String desc = "Failed to mockMultipartFile the image " + filename + " .";
                    System.out.println(desc);
                    throw new IllegalArgumentException(desc, e);
                }
                return multipartFile;
            }).toArray(MultipartFile[]::new);
            System.out.println("cost : " + (System.currentTimeMillis() - startTime));
            return multipartFiles;
        }


        public void toFile(final File outFile) throws IOException {
            Iterator<T> iter = sources.iterator();
            T source = iter.next();
            if (iter.hasNext()) {
                throw new IllegalArgumentException("Cannot create one thumbnail from multiple original images.");
            }
            write(source, ImageIO.createImageOutputStream(outFile));
        }

        private void toFiles(Iterable<File> iterable) throws IOException {
            Iterator<File> filenameIter = iterable.iterator();
            for (T source : sources) {
                if (!filenameIter.hasNext()) {
                    throw new IndexOutOfBoundsException(
                            "Not enough file names provided by iterator."
                    );
                }
                write(source, ImageIO.createImageOutputStream(filenameIter.next()));
            }
        }

        public void toFiles(File destinationDir, String namePrefix) throws IOException {
            if (destinationDir == null && namePrefix == null) {
                throw new NullPointerException("destinationDir and rename is null.");
            }
            if (destinationDir != null && !destinationDir.isDirectory()) {
                destinationDir.mkdir();
//                throw new IllegalArgumentException("Given destination is not a directory.");
            }

            if (destinationDir != null && !destinationDir.isDirectory()) {
                throw new IllegalArgumentException("Given destination is not a directory.");
            }
            long startTime = System.currentTimeMillis();
            Builder<T> builder = outputFormat(outputFormat);
            StreamSupport.stream(sources.spliterator(), true).forEach(source -> {
                if (!(source instanceof File)) {
                    throw new IllegalStateException("Cannot create thumbnails to files if original images are not from files.");
                }
                File f = (File) source;
                File actualDestDir = destinationDir == null ? f.getParentFile() : destinationDir;
                String name = StringUtils.isEmpty(namePrefix) ? f.getName() : namePrefix + f.getName();
                if (!Objects.equals(orgForm, builder.outputFormat)) {
                    name = name.substring(0, name.lastIndexOf(".")) + "." + outputFormat;
                }
                File destinationFile = new File(actualDestDir, name);
                try {
                    System.out.println("Process the image " + f.getName() + " start.");
                    write((T) source, ImageIO.createImageOutputStream(destinationFile));
                } catch (Exception e) {
                    System.out.println("Failed to process the image " + f.getName() + " .");
                    e.printStackTrace();
                }
            });
            System.out.println("cost : " + (System.currentTimeMillis() - startTime));
        }

        public void toOutputStream(final OutputStream outputStream) throws IOException {
            Iterator<T> iter = sources.iterator();
            T source = iter.next();
            if (iter.hasNext()) {
                throw new IllegalArgumentException("Cannot create one thumbnail from multiple original images.");
            }
            write(source, ImageIO.createImageOutputStream(outputStream));
        }

        public void toOutputStreams(Iterable<? extends OutputStream> iterable) throws IOException {
            Iterator<? extends OutputStream> filenameIter = iterable.iterator();
            for (T source : sources) {
                if (!filenameIter.hasNext()) {
                    throw new IndexOutOfBoundsException(
                            "Not enough file names provided by iterator."
                    );
                }
                write(source, ImageIO.createImageOutputStream(filenameIter.next()));
            }
        }
    }
    

参考:
thumbnailator的github地址
java使用google开源工具实现图片压缩
[Java]图片压缩
byte数组、Blob、inputStream、outputStream、MultipartFile之间的转换

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

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

相关文章

Linux多线程Web服务器(C++实现)

本文实现的是基于Reactor模式epoll&#xff08;边缘触发&#xff09;非阻塞socket非阻塞IO线程池的Web服务器&#xff0c;可以处理GET、POST两种请求&#xff0c;完成展示主页、获取图片、获取视频、登录及注册共五种功能。原理图&#xff1a;上图为本文实现的服务器的原理图&a…

国产GPU芯片迎来突破,算力全球第一,中文编程也有好消息

苦&#xff0c;芯片久矣&#xff0c;终&#xff0c;迎来突破&#xff0c;实在振奋人心&#xff01;最近&#xff0c;国产GPU芯片传来了好消息&#xff0c;国产自研首款通用芯片&#xff0c;以每秒千万亿次的计算能力&#xff0c;创全球算力记录&#xff0c;芯片领域实现跨越式的…

包体积优化 · 实战论 · 怎么做包体优化? 做好能晋升吗? 能涨多少钱?

“ 【小木箱成长营】包体积优化系列文章&#xff1a; 包体积优化 方法论 揭开包体积优化神秘面纱 包体积优化 工具论 初识包体积优化 BaguTree 包体积优化录播视频课 ”一、引言 Hello&#xff0c;我是小木箱&#xff0c;欢迎来到小木箱成长营系列教程&#xff0c;今天将分…

论文投稿指南——中文核心期刊推荐(农业工程)

【前言】 &#x1f680; 想发论文怎么办&#xff1f;手把手教你论文如何投稿&#xff01;那么&#xff0c;首先要搞懂投稿目标——论文期刊 &#x1f384; 在期刊论文的分布中&#xff0c;存在一种普遍现象&#xff1a;即对于某一特定的学科或专业来说&#xff0c;少数期刊所含…

实战10:基于opencv的数字图像处理:边缘检测 (完整代码+详细教程)

给出“离散拉普拉斯算子”一般形式的数学推导 离散值的导数使用差分代替: 所以: 以(x, y)为中心点,在水平和垂直方向上应用拉普拉斯算子,滤波器(对应a=1的情况)为:

Spring Cloud Alibaba学习指南

文章目录背景介绍主要功能主要组件参考文档Spring Cloud Alibaba githubNacos官方文档Nacos运维手册Sentinel官方文档Spring Cloud Alibaba SentinelSeata官方文档Spring Cloud Alibaba 英语文档应用脚手架背景 由于在2018年Netflix公司宣布对其核心组件Hystrix、Ribbon、zuul…

远端连接服务器详解

昨天决定入手了一台腾讯轻量应用服务器&#xff0c;在连接的过程中遇到很多问题&#xff0c;浪费了很多时间&#xff0c;所以在这里对这些问题进行整理分享给大家&#xff01;&#xff01;&#xff01;系统的安装OpenCloudOS是完全中立、全面开放、安全稳定、高性能的操作系统及…

JVM调优之GC日志分析及可视化工具介绍

JVM调优之GC日志分析及可视化工具介绍 文章目录JVM调优之GC日志分析及可视化工具介绍GC日志参数GC日志参数常用垃圾收集器参数GC日志分析日志的含义使用 ParNew Serial Old 的组合进行内存回收使用 Parallel Scavenge Parallel Old 的组合进行内存回收大对象回收分析日志分析…

药品溶出曲线数据库

药物在体外的溶出行为&#xff0c;可以用来预测体内的崩解、溶出和吸收情况&#xff0c;同时药物体外溶出行为能够在一定程度上反映出制剂的质量。而溶出曲线特别是不同溶出介质的多条溶出曲线&#xff0c;可更加全面、灵敏地反映出上述关键要素的变化。当药物溶出曲线中药物品…

电脑磁盘重新分配空间的简单步骤(无损数据空间转移)

目录 一、前言 遇到问题 解决方式 二、磁盘现状与实现目标 磁盘现状 实现目标 三、操作步骤 &#xff08;一&#xff09;关闭电脑磁盘加密 &#xff08;二&#xff09;下载安装分区助手 &#xff08;三&#xff09;分配空间教程 注意事项 磁盘空间移动成功 一、前…

芯片设计五部曲之二 | 图灵艺术家——数字IC

《芯片设计五部曲》&#xff1a;模拟IC、数字IC、存储芯片、算法仿真和总结篇&#xff08;排名不分先后 上一集我们已经说了&#xff0c;模拟IC&#xff0c;更像是一种魔法。 我们深度解释了这种魔法的本质&#xff0c;以及如何在模拟芯片设计的不同阶段&#xff0c;根据常见的…

千万别乱用!Lombok不是万能的

背景 在使用Lombok构建无参构造器的时候&#xff0c;同事同时使用了Data和Builder&#xff0c;造成了编译不通过的问题&#xff01; Data使用说明 Lombok的Data注解可以为我们生成无参构造方法和类中所有属性的Getter和Setter方法。这样在我们开发的过程中&#xff0c;我们就…

seaborn的调色板、刻度、边框、标签、数据集等的一些解释

文章目录前言数据集构建整体风格设置调色板x轴的刻度值设置sns.lineplot实例前言 seaborn是对matplotlib进一步封装的库&#xff0c;可以用更少的代码&#xff0c;画出更好看的图。 官网&#xff1a;https://seaborn.pydata.org/index.html 下面记录一下seaborn的基础用法 数…

【日常业务开发】策略+工厂模式优化 if...else判断逻辑

【日常业务开发】策略工厂模式优化 if...else判断逻辑场景策略工厂模式优化利用Spring自动注入的特点处理继承InitializingBean静态工厂方法调用处理注解CommandLineRunnerApplicationContextAware处理/ApplicationListener\<ContextRefreshedEvent>场景 业务中经常有支…

一行代码写一个谷歌插件 —— Javascript

回顾 前期 【提高代码可读性】—— 手握多个代码优化技巧、细数哪些惊艳一时的策略_0.活在风浪里的博客-CSDN博客代码优化对象策略https://blog.csdn.net/m0_57904695/article/details/128318224?spm1001.2014.3001.5501 目录 技巧一&#xff1a;谷歌插件 第一步: 第二步…

Tomcat的安装和使用

作者&#xff1a;~小明学编程 文章专栏&#xff1a;JavaEE 格言&#xff1a;热爱编程的&#xff0c;终将被编程所厚爱。 目录 下载Tomcat tomcat文件介绍 启动Tomcat 简单的部署静态页面 HTTP 服务器&#xff0c;就是在 TCP 服务器的基础上&#xff0c;加上了一些额外的功能…

计算机网络 - 概述

文章目录前言一、计算机网络概述1.1、计算机网络在信息时代的作用1.2、Intnet概述网络、互连网&#xff08;互联网&#xff09;和因特网因特网发展阶段因特网的组成1.3、计算机网络的定义和分类定义分类1.4、报文交换方式电路交换分组交换报文交换三种交换方式对比1.5、性能指标…

5-1输入/输出管理-I/O管理概述

文章目录一.I/O设备二.I/O控制器/设备控制器三.I/O控制方式1.程序直接控制方式2.中断驱动方式3.DMA方式&#xff08;直接存储器存取&#xff09;4.通道控制方式四.I/O子系统的层次结构五.输入/输出应用程序接口&设备驱动程序接口&#xff08;一&#xff09;输入/输出应用程…

【学Vue就跟玩一样】组件-单文件组件

单文件组件在实际开发中是经常使用的&#xff0c;那么如何创建一个单文件组件呢&#xff1f;那么本篇就来简单入一下单文件组件。一&#xff0c;创建单文件组件 1.切换到你想要创建该文件的目录下&#xff0c;我这里切换的是desktop这个目录&#xff0c;当然&#xff0c;也可以…

大学高校供配电系统谐波危害及治理方案

摘要&#xff1a;安全科学用电是保障高校教学科研及办公的基础条件&#xff0c;随着现代化教学、电子图书馆等先进教学手段的不断引入&#xff0c;智能给排水、变频空调、电梯传送系统等配套设施以及电子镇流的照明灯具设备等大量非线性电力电子设备涌现&#xff0c;很多高等院…