自定义复杂图片水印

news2024/11/24 5:30:43

我的社交能力还不如5岁儿童和狗。

文章目录

  • 前言
  • 一、主要工具类
  • 总结


前言

之前写过一些简单的图片压缩和图片加水印:JAVA实现图片质量压缩和加水印

本次主要是针对图片加水印进行一个升级,图片水印自定义,自适应大小。

来,先看几张不同分辨率的图片加过水印的效果

分辨率:1702 x 1276

分辨率:4000 x 3000

分辨率:1080 x 1440

其实大家看右下角,csdn自动给我图片加的水印就能发现,4000*3000的图片几乎都看不到右下角的水印,说明他这个水印不是自适应的。但是我左下角加的,三张图片都是这么大,根据图片自动变化大小。


提示:以下是本篇文章正文内容,下面案例可供参考

一、主要工具类

其中主要是进行了坐标点的计算,通过拼接计算来确定各个水印的坐标点,从而进行绘制。

其中进行了一部分封装

 /**
     * 添加图片文字水印(此方法不在考虑文字过长需要换行等情况)
     *
     * @param targetImg 原图片路径,需要是本地路径,如是网络url需要单独更改
     * @param x         水印x轴坐标
     * @param y         水印y轴坐标
     * @param fontSize  水印文字大小 英镑,会根据图片分辨率自动放大和缩小,只需要指定标准350像素的文字标准值即可
     * @param c         水印文字颜色 例如:Color.WHITE
     * @param fontName  水印文字字体 例如:宋体,微软雅黑
     * @param fontStyle 水印文字字体风格,例如:Font.PLAIN正常字体/BOLD加粗/ITALIC斜体.
     * @param alpha     水印文字透明度,例如: 1.0F,范围 0-1F
     * @param text      水印文字
     */
    public static void pressText(String targetImg, int x, int y, int fontSize, Color c, String fontName
            , int fontStyle, float alpha, String text) {
        try {
            // 读取原图片
            BufferedImage src = ImageIO.read(new File(targetImg));
            // 获取原图的宽和高
            int width = src.getWidth(null);
            int height = src.getHeight(null);
            // 动态设置字体大小
            fontSize = width < height ? width / 350 * fontSize : height / 350 * fontSize;
            // 创建空图片,指定宽高
            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            // 准备绘制图片
            Graphics2D g = image.createGraphics();
            // 将原图绘制到此空图片上,左上角为坐标起点,(0,0),宽和高为原图大小
            g.drawImage(src, 0, 0, width, height, null);
            // 设置水印字体颜色.
            g.setColor(c);
            // 设置水印字体,Font.PLAIN正常字体/BOLD加粗/ITALIC斜体.
            g.setFont(new Font(fontName, fontStyle, fontSize));
            // 透明度
            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
            /* 消除java.awt.Font字体的锯齿 */
            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                    RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
            g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
                    RenderingHints.VALUE_FRACTIONALMETRICS_ON);

            // 添加文字水印
            g.drawString(text, x, y);
            // 输出图像
            g.dispose();
            File f = new File(targetImg);
            // 将加过水印的图片保存到指定文件
            ImageIO.write(image, targetImg.substring(targetImg.lastIndexOf(".") + 1), f);
        } catch (Exception e) {
            log.error("水印添加失败:{}", e.getMessage());
        }
    }

中间还有一部分的坐标点计算,感觉写的有点乱了,没有梳理好,仅供参考。

下面是整个工具类的代码:

package com.example.demo.util;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.Week;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.json.JSONObject;
import lombok.extern.slf4j.Slf4j;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Date;

/**
 * @author GMaya
 * @create 2023/2/22 9:44
 * @Description 类描述: 图片相关的工具类
 */
@Slf4j
public class ImageUtils {


    /**
     * 图片加水印
     *
     * @param json      相关设置
     * @param targetImg 要加水印的图片路径
     * @param staticUrl 静态地址
     */
    public static void pressTexts(JSONObject json, String targetImg, String staticUrl) {

        try {
            long l = System.currentTimeMillis();
            // 读取原图片,获取宽度和高度 TODO 使用BufferedImage中没有exif信息,导致有exif的图片宽和高会读取错误,需要进行修正。目前本地图片修正暂时没有处理。线上图片来源为阿里oss,在链接后拼接自动修正参数即可:?x-oss-process=image/auto-orient,1
//            String uuu = "https://xxx-dev.oss-cn-shanghai.aliyuncs.com/upload/123123/aa/20230223/b811b496cff29f02f0fa5a994c66867e.jpg";
//            String uuu = "https://xxx-dev.oss-cn-shanghai.aliyuncs.com/upload/123123/aa/20230223/b811b496cff29f02f0fa5a994c66867e.jpg?x-oss-process=image/auto-orient,1";
//            URL url = new URL(uuu);
//            BufferedImage src = ImgUtil.read(url);
            BufferedImage src = ImgUtil.read(targetImg);
            int width = src.getWidth(null);
            int height = src.getHeight(null);
            log.info("原图宽:{},高:{}",width,height);
            // 动态设置字体大小 , 以350像素9的基数大小设置
            int fontSize = width < height ? width / 350 * 9 : height / 350 * 9;
            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            Graphics2D g = image.createGraphics();
            // 将原图绘制
            g.drawImage(src, 0, 0, width, height, null);
            // 设置水印字体颜色.
            g.setColor(Color.WHITE);
            // 设置水印字体,Font.PLAIN正常字体/BOLD加粗/ITALIC斜体.
            g.setFont(new Font("微软雅黑", Font.PLAIN, fontSize));
            // 透明度
//            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.9f));
            // 消除java.awt.Font字体的锯齿
            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                    RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
            g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
                    RenderingHints.VALUE_FRACTIONALMETRICS_ON);

            // 比例
            int rat = width < height ? width / 350 : height / 350;
            BufferedImage readAddress = ImgUtil.read(staticUrl + "address.png");
            BufferedImage readUserName = ImgUtil.read(staticUrl + "userName.png");
            BufferedImage readCompanyName = ImgUtil.read(staticUrl + "companyName.png");
            BufferedImage readFloor = ImgUtil.read(staticUrl + "floor.png");
            int imageWidth = rat * 6;
            int imageHeight = rat * 7;

            // 计算各个坐标点
            int xx1 = 0; // 姓名图标
            int yy1 = 0; // 姓名图标
            int xx2 = 0; // 姓名
            int yy2 = 0; // 姓名

            int xx3 = 0; // 公司图标
            int yy3 = 0; // 公司图标
            int xx4 = 0; // 公司
            int yy4 = 0; // 公司

            int xx5 = 0; // 地址图标
            int yy5 = 0; // 地址图标
            int xx6 = 0; // 地址
            int yy6 = 0; // 地址

            int xx7 = 0; // 左侧竖线
            int yy7 = 0; // 左侧竖线
            int xx8 = 0; // 拍照标签
            int yy8 = 0; // 拍照标签

            int xx9 = 0; // logo图标
            int yy9 = 0; // logo图标

            int xx10 = 32; // 年月日坐标
            int yy10 = 0; // 年月日坐标

            int xx11 = 32; // 时分秒坐标
            int yy11 = 0; // 时分秒坐标

            int w12 = 0; // 底板宽 底板坐标点无需计算,但是底板的宽高需要计算
            int h12 = 0; // 底板高

            int sd = 0; // 标准差
            // 公共坐标计算点 xx为图标,xxx为文字
            int xx = 0;
            int yy = 0;
            int xxx = 0;
            int yyy = 0;

            // 提前计算出各个坐标点
            for (int i = 0; i < 7; i++) {
                if (i == 0) {
                    // 用户名称
                    String userNameIsShow = json.getStr("userNameIsShow");
                    if ("0".equals(userNameIsShow)) {
                        // x轴默认距离左边16*比例
                        xx1 = 10 * rat;
                        yy1 = height - (10 * rat) - imageHeight;
                        xx = xx1;
                        yy = yy1;
                        xx2 = 10 * rat + imageWidth + (4 * rat);
                        yy2 = height - (10 * rat);
                        xxx = xx2;
                        yyy = yy2;
                    }
                    continue;

                }
                if (i == 1) {
                    // 公司名称
                    String companyNameIsShow = json.getStr("companyNameIsShow");
                    if ("0".equals(companyNameIsShow)) {
                        // 如果公司展示,则需要判断上一个用户字段是否展示,如果展示和不展示,x,y轴坐标将不一样
                        if (xx == 0) {
                            xx3 = 10 * rat;
                            yy3 = height - (10 * rat) - imageHeight;
                            xx = xx3;
                            yy = yy3;
                            xx4 = 10 * rat + imageWidth + (4 * rat);
                            yy4 = height - (10 * rat);
                            xxx = xx4;
                            yyy = yy4;
                        } else {
                            xx3 = xx;
                            yy3 = yy - (5 * rat) - imageHeight;
                            yy = yy3;
                            xx4 = xxx;
                            yy4 = yyy - (5 * rat) - fontSize;
                            yyy = yy4;
                        }
                    }
                    continue;

                }
                if (i == 2) {
                    // 全部默认0是,1否
                    String addressIsShow = json.getStr("addressIsShow");
                    if ("0".equals(addressIsShow)) {


                        // 此处定义最高位置的地址即可,换行的在真正生成时进行处理
                        String address = json.getStr("address");
                        int maxLength = 13;
                        // 计算出地址的占用行数
                        int i2 = address.length() / maxLength + (address.length() % maxLength == 0 ? 0 : 1);

                        if (xx == 0) {
                            // 公司和姓名都不展示
                            xx5 = 10 * rat;
                            yy5 = height - 12 - (fontSize * i2);

                            xx6 = 10 * rat + imageWidth + 10;
                            yy6 = height - (12 * (i2 + 1)) - (fontSize * (i2 + 1));
                            xxx  = xx6;
                            yyy = yy6;
                            continue;
                        } else {
                            xx5 = xx;
                            yy5 = yy - 12 - (fontSize * i2);
                            yy = yy5;
                            xx6 = xxx;
                            yy6 = yyy - (12 * (i2 + 1)) - (fontSize * (i2 + 1));
                            yyy = yy6;
                        }

                    }

                }

                if (i == 5) {
                    // 时间控制
                    String timeIsShow = json.getStr("timeIsShow");
                    if ("0".equals(timeIsShow)) {
                        xx10 = xx;
                        xx11 = xx;

                        if (xx == 0) {
                            yy10 = height - (10 * rat);
                            yy11 = yy10 - fontSize - 8 * rat;
                        }else{
                            yy10 = yyy - (8 * rat);
                            yy11 = yy10 - fontSize - 8 * rat;
                        }
                        yyy = yy11;
                        yy = yy11;
                    }
                    continue;
                }

                if (i == 6) {
                    // 计算地图蒙版,需要在所有坐标计算后,在计算地图大小
                    // 缩放比例
                    int i1 = width < height ? width / 350 : height / 350;
                    w12 = readFloor.getWidth() * i1 / 3 * 2 ;
                    String timeIsShow = json.getStr("timeIsShow");
                    if ("0".equals(timeIsShow)) {
                        h12 = height - yyy  + (i1 * 18);
                        continue;
                    }


                    String addressIsShow = json.getStr("addressIsShow");
                    String companyNameIsShow = json.getStr("companyNameIsShow");
                    String userNameIsShow = json.getStr("userNameIsShow");

                    if("0".equals(addressIsShow) || "0".equals(companyNameIsShow) ||"0".equals(userNameIsShow)){
                        h12 = height - yyy - 6 + 30;
                    }
                    System.out.println(h12);
                    continue;
                }

            }

            for (int i = 0; i < 6; i++) {

                if (i == 1) {
                    // 优先绘制底板
                    String addressIsShow = json.getStr("addressIsShow");
                    String companyNameIsShow = json.getStr("companyNameIsShow");
                    String userNameIsShow = json.getStr("userNameIsShow");
                    String timeIsShow = json.getStr("timeIsShow");
                    if (!"0".equals(addressIsShow) && !"0".equals(companyNameIsShow) && !"0".equals(userNameIsShow) &&
                            !"0".equals(timeIsShow)) {
                        // 如果所有的都关闭,则无需添加底板和水印,直接跳出循环,结束水印绘制。
                        break;
                    }

                    g.drawImage(readFloor, 6 * rat, height - h12, w12, h12 - 6 * rat, null);
                    continue;
                }

                if (i == 2) {
                    // 全部默认0是,1否
                    String userNameIsShow = json.getStr("userNameIsShow");
                    if ("0".equals(userNameIsShow)) {
                        String userName = json.getStr("userName");
                        g.drawImage(readUserName, xx1, yy1,imageWidth,imageHeight, null);
                        g.drawString(userName, xx2, yy2);
                    }
                    continue;

                }
                if (i == 3) {
                    // 全部默认0是,1否
                    String companyNameIsShow = json.getStr("companyNameIsShow");
                    if ("0".equals(companyNameIsShow)) {
                        String companyName = json.getStr("companyName");
                        g.drawImage(readCompanyName, xx3, yy3,imageWidth,imageHeight, null);
                        g.drawString(companyName, xx4, yy4);
                    }
                    continue;

                }
                if (i == 4) {
                    // 全部默认0是,1否
                    String addressIsShow = json.getStr("addressIsShow");
                    if ("0".equals(addressIsShow)) {
                        String address = json.getStr("address");
                        int maxLength = 13;
                        // 计算出地址的占用行数
                        int i2 = address.length() / maxLength + (address.length() % maxLength == 0 ? 0 : 1);
                        int len = 0;
                        for (int j = i2 - 1; j >= 0; j--) {
                            int mlen = maxLength * (j + 1);
                            len = j * maxLength;
                            if (mlen < address.length()) {
                                g.drawString(address.substring(len, mlen), xx6, yy6 + (fontSize * (j + 1)));
                            } else {
                                g.drawString(address.substring(len), xx6, yy6 + (fontSize * (j + 1)));
                            }
                        }

                        // 图标
                        g.drawImage(readAddress, xx5, yy5,imageWidth,imageHeight, null);

                    }
                    continue;
                }
            }
            // 输出图像
            g.dispose();
            File f = new File(targetImg);
            ImageIO.write(image, targetImg.substring(targetImg.lastIndexOf(".") + 1), f);
            // 如果年月日展示,则进行坐标计算
            String timeIsShow = json.getStr("timeIsShow");
            if ("0".equals(timeIsShow)) {
                String s = DateUtil.formatDate(new Date());
                Week week = DateUtil.dayOfWeekEnum(new Date());
                // 文字水印为:2023-02-22  星期三
                pressText(targetImg, xx10, yy10, 12, Color.WHITE, "微软雅黑", Font.PLAIN, 0.9F, s + "  " + week.toChinese());
                String time = DateUtil.format(new Date(), "HH:mm:ss");

                pressText(targetImg, xx11, yy11, 18, Color.WHITE, "微软雅黑", Font.BOLD, 0.9F, time);
            }
            //花费毫秒数
            long ll = System.currentTimeMillis();
            log.info("图片加水印耗时:{}{}", ll - l, "ms");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 添加图片文字水印(此方法不在考虑文字过长需要换行等情况)
     *
     * @param targetImg 原图片路径,需要是本地路径,如是网络url需要单独更改
     * @param x         水印x轴坐标
     * @param y         水印y轴坐标
     * @param fontSize  水印文字大小 英镑,会根据图片分辨率自动放大和缩小,只需要指定标准350像素的文字标准值即可
     * @param c         水印文字颜色 例如:Color.WHITE
     * @param fontName  水印文字字体 例如:宋体,微软雅黑
     * @param fontStyle 水印文字字体风格,例如:Font.PLAIN正常字体/BOLD加粗/ITALIC斜体.
     * @param alpha     水印文字透明度,例如: 1.0F,范围 0-1F
     * @param text      水印文字
     */
    public static void pressText(String targetImg, int x, int y, int fontSize, Color c, String fontName
            , int fontStyle, float alpha, String text) {
        try {
            // 读取原图片
            BufferedImage src = ImageIO.read(new File(targetImg));
            // 获取原图的宽和高
            int width = src.getWidth(null);
            int height = src.getHeight(null);
            // 动态设置字体大小
            fontSize = width < height ? width / 350 * fontSize : height / 350 * fontSize;
            // 创建空图片,指定宽高
            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            // 准备绘制图片
            Graphics2D g = image.createGraphics();
            // 将原图绘制到此空图片上,左上角为坐标起点,(0,0),宽和高为原图大小
            g.drawImage(src, 0, 0, width, height, null);
            // 设置水印字体颜色.
            g.setColor(c);
            // 设置水印字体,Font.PLAIN正常字体/BOLD加粗/ITALIC斜体.
            g.setFont(new Font(fontName, fontStyle, fontSize));
            // 透明度
            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
            /* 消除java.awt.Font字体的锯齿 */
            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                    RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
            g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
                    RenderingHints.VALUE_FRACTIONALMETRICS_ON);

            // 添加文字水印
            g.drawString(text, x, y);
            // 输出图像
            g.dispose();
            File f = new File(targetImg);
            // 将加过水印的图片保存到指定文件
            ImageIO.write(image, targetImg.substring(targetImg.lastIndexOf(".") + 1), f);
        } catch (Exception e) {
            log.error("水印添加失败:{}", e.getMessage());
        }
    }


    /**
     * 计算文字长度,一个中文按两个长度,英文按一个长度计算
     *
     * @param text 文字
     * @return
     */
    public static int getLength(String text) {
        int length = 0;
        for (int i = 0; i < text.length(); i++) {
            if (new String(text.charAt(i) + "").getBytes().length > 1) {
                length += 2;
            } else {
                length += 1;
            }
        }
        return length / 2;
    }


    /**
     * 导出zip压缩包
     *
     * @param srcPath  要压缩的文件夹路径
     * @param response 输出流
     */
    public static void downloadZip(String srcPath, HttpServletResponse response) {

        // 将此目录打包成zip
        File file = ZipUtil.zip(srcPath);

        OutputStream toClient = null;
        try {
            // 以流的形式下载文件。
            BufferedInputStream fis = new BufferedInputStream(new FileInputStream(file.getPath()));
            byte[] buffer = new byte[fis.available()];
            fis.read(buffer);
            fis.close();
            // 清空response
            response.reset();
            toClient = new BufferedOutputStream(response.getOutputStream());
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/zip");
            response.setHeader("Content-Disposition", "attachment;filename=" + file.getName());
            toClient.write(buffer);
            toClient.flush();
        } catch (Exception e) {
            log.error("下载zip压缩包过程发生异常:", e);
        } finally {
            if (toClient != null) {
                try {
                    toClient.close();
                } catch (IOException e) {
                    log.error("zip包下载关流失败:", e);
                }
            }
            //删除改临时zip包(此zip包任何时候都不需要保留,因为源文件随时可以再次进行压缩生成zip包)
            file.delete();
        }
    }

}

总结

其中,通过ImageIO.read读取的图片,是没有exif信息的,这样就会导致有exif的图片,读取后宽和高可能不准确,最终生成的图片就是未旋转的,看起来就是颠倒的。如果有谁有办法处理本地图片exif问题,可以回复下。
让我学习学习。
如果使用的是阿里云oss地址,在后面拼接参数即可:
例如:

String uuu = "https://xxx-dev.oss-cn-shanghai.aliyuncs.com/upload/123123/aa/20230223/b811b496cff29f02f0fa5a994c66867e.jpg";
String uuu = "https://xxx-dev.oss-cn-shanghai.aliyuncs.com/upload/123123/aa/20230223/b811b496cff29f02f0fa5a994c66867e.jpg?x-oss-process=image/auto-orient,1";

在oss地址后面拼接?x-oss-process=image/auto-orient,1 即可。阿里云oss自适应传送门

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

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

相关文章

JS语法让人困惑的点 “==与===”

在JS中有很多神奇的语法&#xff0c;非常让人困惑&#xff0c;我们就先一一道来&#xff0c;相信你在开发中或多或少都踩过这些坑&#xff0c;或者让人无法理解。 今天我们就来说下【】和【】 这题对于很多没有系统学过前端开发的技术人员来说&#xff0c;算个重点&#xff0c…

LLFlow沦为和代码解读

LLFlow沦为和代码解读 1.测试时代码的运行位置 sr&#xff1a;什么意思 sr 和 z 这里又将模型设置为了训练模式 所以下面这部分代码应该是测试时运行的所有代码 这个就是测试时使用的网络模型框架 下面应该就是self.netG的网络模型框架 但是这个z的网络模型框架代码还不…

前端基础之HTML扫盲

文章目录一. 第一个HTML程序1. 创建一个HTML文件并运行2. HTML的基本结构二. HTML常见标签1. 注释标签2. 标题标签3. 段落标签4. 换行标签5. 格式化标签6. 图片标签7. 超链接标签8. 表格标签9. 列表标签10. 表单标签10.1 input标签10.2 select标签10.3 textarea标签11. 无语义标…

Outlook账号被封?别慌,一步步教你怎么申诉

相信很多兄弟们使用Outlook不止是为了注册第三方平台&#xff0c;很多时候还会用来发送一些营销广告。但是广告邮件发多了很容易被官方检测到并查封。龙哥考虑到这个问题&#xff0c;就干脆给兄弟们也出一份Outlook的申诉教程&#xff0c;保证大家都从注册、养号、防关联到解封…

DataGear 使用数据集计算属性功能制作数据可视化图表

DataGear 在4.5.0版本新增了数据集计算属性特性&#xff0c;支持在定义数据集时对原始数据进行二次计算处理。 利用这一特性&#xff0c;可以更加方便灵活地制作数据可视化图表。 本文以某公司近两年季度销售额Excel为例&#xff0c;介绍如何基于数据集计算属性功能制作数据可…

Vue跨级通信(重点)

当不使用Vuex的前提下&#xff0c;子孙传递就得使用另外一种办法&#xff1a;provide 和 inject 总结&#xff1a;provide / inject 类似于消息的订阅和发布。- inject接收数据。- provide提供或发送数据&#xff0c;&#xff08;1&#xff09;provide&#xff08;name&#xf…

Dubbo性能调优参数以及原理

Dubbo作为一个服务治理框架&#xff0c;功能相对来说比较完善&#xff0c;性能也挺不错。但很多同学在使用dubbo的时候&#xff0c;只是简单的参考官方说明进行配置和应用&#xff0c;并没有过多的去思考一些关键参数的意义&#xff0c;最终做出来的效果总是差强人意,接下来我们…

扬帆优配|反弹涨超70%,昨收三连板,稀土行业或迎大事件

本年第一批稀土挖掘锻炼目标行将发放。 2月22日晚&#xff0c;东易日盛公告称&#xff0c;公司收到董事、副总经理兼财务总监李双侠出具的《关于未严格执行股份减持方案的致歉函》&#xff0c;其此次减持方案已施行结束&#xff0c;但在施行减持方案时&#xff0c;因操作失误&a…

从没想过开源 API 工具的 Mock 功能,这么好用

很多时候&#xff0c;接口尚未开发完成&#xff0c;在系统交互双方定义好接口之后&#xff0c;我们可以提前进行开发和测试&#xff0c;并不依赖上游系统的开发实现。 通过使用Mock模拟数据接口&#xff0c;我们即可在只开发了UI的情况下&#xff0c;无须服务端的开发就可以进行…

证明CPU指令是乱序执行的

承接上文CPU缓存一致性原理双击QQ.exe从磁盘加载到内存里面&#xff0c;内存里面就会有了一个进程&#xff0c;进程产生的时候会产生一个主线程&#xff0c;就是main方法所在的线程&#xff0c;cpu会找到main开始的地方&#xff0c;把它的指令读取过来放到程序计数器&#xff0…

从功能测试进阶自动化测试,熬夜7天整理出这一份3000字超全学习指南

一、为什么要学习自动化测试&#xff1f; 如果在前两年&#xff0c;可能10个测试员有6个都是做的功能测试&#xff0c;但随着测试技术的发展以及测试工作的深入&#xff0c;传统的手工测试已经无法满足多模块的测试需求&#xff0c;所以为了提高测试效率和测试质量&#xff0c…

关于 mac 本地配置域名能 ping 通,但是浏览器不能访问的问题(而其他电脑操作可访问)

关于 mac 本地配置域名能 ping 通&#xff0c;但是浏览器不能访问的问题&#xff08;而其他电脑操作可访问&#xff09;1. 配置域名的方式1.1 sudo vim /etc/hosts1.2 浏览器插件 LiveHosts2. 问题描述3. 解决问题方法3.1 尝试方法1—确保代理都关闭3.2 尝试方法2—确保域名能p…

一文学会 Spring 整合 MyBatis

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

js闭包简单理解

js里面的闭包是一个难点也是它的一个特色&#xff0c;是我们必须掌握的js高级特性&#xff0c;那么什么是闭包呢&#xff1f;它又有什么作用呢&#xff1f; 1&#xff0c;提到闭包我们这里先讲解一下js作用域的问题 js的作用域分两种&#xff0c;全局和局部&#xff0c;基于我…

代码随想录第十六天(347、194、195、94)

347. 前 K 个高频元素 答案 思路&#xff1a; 1、首先&#xff0c;用到了每个值对应的出现次数&#xff0c;想到要用哈希map存放 2、还需要将出现频率从大到小进行排序&#xff0c;找出前k个元素 3、时间复杂度应该比O&#xff08;nlogn&#xff09;小 如果想用快速排序&…

黑盒渗透盲打lampiao

一、查找主机ip&#xff0c;通过Nmap扫描工具排查出我的靶机的IP 为.134 python tools.py ip -i 192.168.12.0 -h 254 -l 1 二、扫描其他端口。 1898 三、查看网站漏洞情况&#xff0c;典型的漏洞特征 Ac扫描漏洞情况&#xff0c;利用典型的漏洞。 四、开始getshell 1、启动M…

SigmaPlot科学绘图工具:ROC曲线分析及AUC组间差异的显著性分析

目的 初步使用SigmaPlot科学绘图工具&#xff1b;进行ROC曲线绘制并分析检验变量AUC组间差异性是否显著 软件下载及安装 SigmaPlot下载安装按照这个教程即可&#xff1a;https://www.hhkxxw.com/24799.html 快速通道&#xff1a;SigmaPlot下载链接&#xff1a;百度网盘链接…

如何实现文件高速传输,推荐镭速高速文件传输解决方案

随着互联网的发展&#xff0c;文件传输越来越频繁&#xff0c;如何实现文件高速传输已经越来越成为企业发展过程中需要解决的问题&#xff0c; 在当今的业务中&#xff0c;随着与客户和供应商以及内部系统的所有通信的数据量不断增加&#xff0c;对高速文件传输解决方案的需求…

Prometheus之Alertmanager告警

告警流程 Prometheus主要是提供了数据的采集和存储&#xff0c;Alertmanager组件主要实现告警功能。Alertmanager 主要用于接收 Prometheus 发送的告警信息&#xff0c;它支持丰富的告警通知渠道&#xff0c;而且很容易做到告警信息进行去重&#xff0c;降噪&#xff0c;分组等…

Elasticsearch 基础(三)之相关术语概念及原理

目录前言一、集群1、相关术语概念1.1、集群&#xff08;Cluster&#xff09;1.2、节点&#xff08;Node&#xff09;1.3、角色&#xff08;Roles&#xff09;1.4、分片&#xff08;Shard&#xff09;2、集群场景及原理2.1、集群健康2.2、空节点2.3、单节点2.4、集群追加节点2.5…