实践经验

目录:

一、Mybatis的forEach使用详细

二、正则表达式

三、Ajax

四、JMX(jconsole)

五、二维码生成

六、AtomicInteger 原子性数值

七、DocumentHelper,XML解析

八、Jackson,Json解析

九、Mina框架

A、一致性哈希算法+哈希槽算法

B、RMI(调用接口)

C、布隆过滤器

D、Nacos

Mybatis的forEach使用详细:

在需要传入多个数据到Mybatis中是用到

在Collection层中:

HashMap<String, List<Integer>> map = new HashMap<>();//建立Map
ArrayList<Integer> list = new ArrayList<>();//建立List
map.put("haha",list);//添加list到map中 命名为haha

 在Mapper.xml中

 <delete id="deleteByPrimaryKey" parameterType="list">
    delete
from gzcrm_cmresults
<where> <foreach collection="haha" item="list" open="and (" close=")" separator="or"> cm_key = #{list,jdbcType=INTEGER} </foreach> </where> </delete>

 ♥正则表达式

HTML:

<form action="">
    <input type="text" pattern="\d{2}">
    <input type="submit" value="提交">
</form>

 

Java:

        String srt = "142-66";
        System.out.println(srt.matches(".{2}-\\d{3}||\\d{3}-\\d{2}"));
        System.out.println(Pattern.matches("^123\\w{1}$", "123L"));//^$

String text = "北京市()北京市(海淀区)(朝阳区)(西城区)";
Pattern pattern = Pattern.compile("北.*?市(?=\\()" );//零宽断言:(?=exp)、(?<=exp)、贪婪与懒惰
Matcher matcher = pattern.matcher(text);
if (matcher.find()) {
System.out.println(matcher.group(0));
}

 ♥Ajax

        function select() {
            $.post({
                url:"${pageContext.request.contextPath}/zhengjianS",//地址
                data:{"id":$("#cate_id").val(),"year":$("#cate_year").val()},
// 在Controller层中直接接受参数public List<GzcrmCertificate> selectAll2(String id, String year){} success:function (data) { var html=""; console.log(data); for(var i=0;i
<data.length;i++){
//取值时用返回对象的字段取值 var d2=new Date(data[i].cmModificationDate); html+="<tr>\n" + "<td><input name=\"checkbox2\" id=\"checkbox2\" type=\"checkbox\" value="+data[i].cmKey+" /></td>\n" + "<td>"+data[i].cmId+"</td>\n" + "<td>"+data[i].cmCertificateName+"</td>\n" + "<td>"+data[i].cmCertificateType+"</td>\n" + "<td>"+data[i].cmCertificateNo+"</td>\n" + "<td>"+data[i].cmCertificateUnit+"</td>\n" + "<td>"+data[i].cmPeriod+"</td>\n" + "<td>"+data[i].cmCertificateUrl+"</td>\n" + "<td>"+d2.getFullYear()+"-"+[d2.getMonth()+1]+"-"+d2.getDate()+"</td>\n" +
//日期的展示(注意在这里的月份从0-11月份用[]对其数字加以) "
<td>"+data[i].cmModificationPerson+"</td>\n" + "</tr>" } $("#list2").html(html);
//修改html、动态修改页面 } }) }


 ♥JMX

1、新建接口(JMXServiceMXBean ),放接口,Jconsole调用。(类名随便)

public interface JMXServiceMXBean {
    public void getLeng();
}

 

2、实现接口(JMXService ),注册JMX,实现类逻辑。

public class JMXService implements JMXServiceMXBean {
    @Override
    public void getLeng(){
        System.out.println("进入接口");
    }
}

 

3、建立初始化

public class ServiceInit {
    public static void startService() {
//        MBeanAgent.registMBeanServiceByJMXMP("127.0.0.1", 3333, "FCU:type=JMXService", new JMXService());
        MBeanAgent.registMBeanService("MyJMX:type=JMXService", new JMXService());
    }
}

 

封装注册类

public class MBeanAgent {
    public static void registMBeanServiceByJMXMP(String host, int port, String key, Object service) {
        try {
            MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
            Map<String, Object> env =  new HashMap<String, Object>();
            env.put("com.sun.management.jmxremote.authenticate", "false");
            env.put("jmx.remote.server.address.wildcard", "false");
            JMXServiceURL jmxURL = null;
            jmxURL = new JMXServiceURL("jmxmp", host, port);
            JMXConnectorServer connectServer = JMXConnectorServerFactory.newJMXConnectorServer(jmxURL, env, mbs);
            connectServer.start();
            ObjectName name = new ObjectName(key);
            if (!mbs.isRegistered(name)) {
                mbs.registerMBean(service, name);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public static void registMBeanService(String key, Object service) {
        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
        try {
            ObjectName name = new ObjectName(key);
            if (!mbs.isRegistered(name)) {
                mbs.registerMBean(service, name);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 

4、启动服务器端

启动时需要指定参数:

-Dcom.sun.management.jmxremote.port=22001
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.hostname=127.0.0.1
-Dcom.sun.management.jmxremote.authenticate=false

public static void main(String[] args) {
  ServiceInit.startService();
    try {
        Thread.sleep(9999999999999999L);
    } catch (InterruptedException e) {
  }
}

 

5、启动客户端,调用函数

        try {
            String jmxUrl = "service:jmx:rmi:///jndi/rmi://127.0.0.1:22001/jmxrmi";
            JMXConnector connector = null;
            Object result = null;
            JMXServiceURL address;
            try {
                String objectName = "MyJMX:type=JMXService";
                String operationName = "getLeng";
                Object[] params = new Object[]{};
                String[] signature = new String[]{};
                address = new JMXServiceURL(jmxUrl);
                connector = JMXConnectorFactory.connect(address);
                ObjectName name = new ObjectName(objectName);
                MBeanServerConnection mbs = connector.getMBeanServerConnection();
                result = mbs.invoke(name, operationName, params, signature);
                System.out.println(result);
            } catch (Exception e) {
                throw e;
            } finally {
                if (null != connector) {
                    connector.close();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

 

 二、HtmlAdaptorServer

 依赖:

<dependency>
    <groupId>com.sun.jdmk</groupId>
    <artifactId>jmxtools</artifactId>
    <version>1.2.1</version>
</dependency>

 

应用:

    public static void main(String[] args) {
        //创建服务
        System.out.println("CREATE the MBeanServer.");
        MBeanServer server = MBeanServerFactory.createMBeanServer();
        //注册并启动
        System.out.println("CREATE, REGISTER and START a new HTML adaptor:");
        HtmlAdaptorServer html = new HtmlAdaptorServer();
        ObjectName html_name = null;
        try {
            html_name = new ObjectName("Adaptor:name=wgyhtml,port=8082");
            System.out.println("OBJECT NAME= " + html_name);
            server.registerMBean(html, html_name);
            html.start();
        } catch (Exception e) {
            System.out.println("!!! Could not create the HTML adaptor !!!");
            e.printStackTrace();
            return;
        }
    }

 

登录网页,访问端口,内容如jconsole

 

二维码生成

导入依赖:

        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>core</artifactId>
            <version>3.3.0</version>
        </dependency>

 

需要建三个类:

1:

package tWeiM;

import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import com.google.zxing.LuminanceSource;

public class T extends LuminanceSource {

    private final BufferedImage image;
    private final int left;
    private final int top;

    public T(BufferedImage image) {
        this(image, 0, 0, image.getWidth(), image.getHeight());
    }

    public T(BufferedImage image, int left, int top, int width, int height) {
        super(width, height);

        int sourceWidth = image.getWidth();
        int sourceHeight = image.getHeight();
        if (left + width > sourceWidth || top + height > sourceHeight) {
            throw new IllegalArgumentException("Crop rectangle does not fit within image data.");
        }

        for (int y = top; y < top + height; y++) {
            for (int x = left; x < left + width; x++) {
                if ((image.getRGB(x, y) & 0xFF000000) == 0) {
                    image.setRGB(x, y, 0xFFFFFFFF); // = white
                }
            }
        }

        this.image = new BufferedImage(sourceWidth, sourceHeight, BufferedImage.TYPE_BYTE_GRAY);
        this.image.getGraphics().drawImage(image, 0, 0, null);
        this.left = left;
        this.top = top;
    }

    public byte[] getRow(int y, byte[] row) {
        if (y < 0 || y >= getHeight()) {
            throw new IllegalArgumentException("Requested row is outside the image: " + y);
        }
        int width = getWidth();
        if (row == null || row.length < width) {
            row = new byte[width];
        }
        image.getRaster().getDataElements(left, top + y, width, 1, row);
        return row;
    }

    public byte[] getMatrix() {
        int width = getWidth();
        int height = getHeight();
        int area = width * height;
        byte[] matrix = new byte[area];
        image.getRaster().getDataElements(left, top, width, height, matrix);
        return matrix;
    }

    public boolean isCropSupported() {
        return true;
    }

    public LuminanceSource crop(int left, int top, int width, int height) {
        return new T(image, this.left + left, this.top + top, width, height);
    }

    public boolean isRotateSupported() {
        return true;
    }

    public LuminanceSource rotateCounterClockwise() {
        int sourceWidth = image.getWidth();
        int sourceHeight = image.getHeight();
        AffineTransform transform = new AffineTransform(0.0, -1.0, 1.0, 0.0, 0.0, sourceWidth);
        BufferedImage rotatedImage = new BufferedImage(sourceHeight, sourceWidth, BufferedImage.TYPE_BYTE_GRAY);
        Graphics2D g = rotatedImage.createGraphics();
        g.drawImage(image, transform, null);
        g.dispose();
        int width = getWidth();
        return new T(rotatedImage, top, sourceWidth - (left + width), getHeight(), width);
    }

}

2:

package tWeiM;


import com.google.zxing.*;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.OutputStream;
import java.util.Hashtable;

public class QRCodeUtil {
    private static final String CHARSET = "utf-8";
    private static final String FORMAT_NAME = "JPG";
    // 二维码尺寸
    private static final int QRCODE_SIZE = 300;
    // LOGO宽度
    private static final int WIDTH = 60;
    // LOGO高度
    private static final int HEIGHT = 60;

    private static BufferedImage createImage(String content, String imgPath, boolean needCompress) throws Exception {
        Hashtable hints = new Hashtable();
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
        hints.put(EncodeHintType.MARGIN, 1);
        BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE,
                hints);
        int width = bitMatrix.getWidth();
        int height = bitMatrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
            }
        }
        if (imgPath == null || "".equals(imgPath)) {
            return image;
        }
        // 插入图片
        QRCodeUtil.insertImage(image, imgPath, needCompress);
        return image;
    }

    private static void insertImage(BufferedImage source, String imgPath, boolean needCompress) throws Exception {
        File file = new File(imgPath);
        if (!file.exists()) {
            System.err.println("" + imgPath + "   该文件不存在!");
            return;
        }
        Image src = ImageIO.read(new File(imgPath));
        int width = src.getWidth(null);
        int height = src.getHeight(null);
        if (needCompress) { // 压缩LOGO
            if (width > WIDTH) {
                width = WIDTH;
            }
            if (height > HEIGHT) {
                height = HEIGHT;
            }
            Image image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH);
            BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            Graphics g = tag.getGraphics();
            g.drawImage(image, 0, 0, null); // 绘制缩小后的图
            g.dispose();
            src = image;
        }
        // 插入LOGO
        Graphics2D graph = source.createGraphics();
        int x = (QRCODE_SIZE - width) / 2;
        int y = (QRCODE_SIZE - height) / 2;
        graph.drawImage(src, x, y, width, height, null);
        Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);
        graph.setStroke(new BasicStroke(3f));
        graph.draw(shape);
        graph.dispose();
    }

    public static void encode(String content, String imgPath, String destPath, boolean needCompress) throws Exception {
        BufferedImage image = QRCodeUtil.createImage(content, imgPath, needCompress);
        mkdirs(destPath);
        // String file = new Random().nextInt(99999999)+".jpg";
        // ImageIO.write(image, FORMAT_NAME, new File(destPath+"/"+file));
        ImageIO.write(image, FORMAT_NAME, new File(destPath));
    }

    public static BufferedImage encode(String content, String imgPath, boolean needCompress) throws Exception {
        BufferedImage image = QRCodeUtil.createImage(content, imgPath, needCompress);
        return image;
    }

    public static void mkdirs(String destPath) {
        File file = new File(destPath);
        // 当文件夹不存在时,mkdirs会自动创建多层目录,区别于mkdir.(mkdir如果父目录不存在则会抛出异常)
        if (!file.exists() && !file.isDirectory()) {
            file.mkdirs();
        }
    }

    public static void encode(String content, String imgPath, String destPath) throws Exception {
        QRCodeUtil.encode(content, imgPath, destPath, false);
    }
    public static void encode(String content, String destPath) throws Exception {
        QRCodeUtil.encode(content, null, destPath, false);
    }

    public static void encode(String content, String imgPath, OutputStream output, boolean needCompress)
            throws Exception {
        BufferedImage image = QRCodeUtil.createImage(content, imgPath, needCompress);
        ImageIO.write(image, FORMAT_NAME, output);
    }

    public static void encode(String content, OutputStream output) throws Exception {
        QRCodeUtil.encode(content, null, output, false);
    }

    public static String decode(File file) throws Exception {
        BufferedImage image;
        image = ImageIO.read(file);
        if (image == null) {
            return null;
        }
        T source = new T(image);
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
        Result result;
        Hashtable hints = new Hashtable();
        hints.put(DecodeHintType.CHARACTER_SET, CHARSET);
        result = new MultiFormatReader().decode(bitmap, hints);
        String resultStr = result.getText();
        return resultStr;
    }

    public static String decode(String path) throws Exception {
        return QRCodeUtil.decode(new File(path));
    }

}

 

3:

package tWeiM;

public class M {
    public static void main(String[] args) throws Exception {
        // 存放在二维码中的内容
        String text = "https://www.zhihu.com/people/wang-la-la-44-5";
        // 嵌入二维码的图片路径
        String imgPath = "E:/Tweima/yu.jpg";
        // 生成的二维码的路径及名称
        String destPath = "E:/Tweima/jam.png";
        //生成二维码
        QRCodeUtil.encode(text, imgPath, destPath, true);
        // 解析二维码
        String str = QRCodeUtil.decode(destPath);
        // 打印出解析出的内容
        System.out.println(str);
    }
}

 

六、AtomicInteger

        AtomicInteger atomicInteger = new AtomicInteger(10);
        //加之前获取类似于i++
        System.out.println(atomicInteger.getAndIncrement());
        //先加后返回,类似以++i
        System.out.println(atomicInteger.addAndGet(1));
        //自增1
        System.out.println(atomicInteger.decrementAndGet());
        //返回结果,两者本质为get()
        int i = atomicInteger.get();
        int i1 = atomicInteger.intValue();

 

七、DocumentHelper

 String xmlMsg = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><tasks><pojo id=\"1\"><name>  666</name><pw>  123</pw></pojo></tasks>";
        //使用工具解析
        Document dom = DocumentHelper.parseText(xmlMsg);
        //获取根rootElement
        Element rootElement = dom.getRootElement();
        List<Element> tasks = rootElement.elements();
        //遍历
        Iterator<Element> it = tasks.iterator();
        while (it.hasNext()) {
            Element ele =it.next();
            //输出自带的属性  例如其中的id   <pojo id="1">
            System.out.println(ele.getName()+":");
            for (Object value : ele.attributes()) {
                Attribute attribute=(Attribute)value;
                System.out.println(attribute.getName()+":"+attribute.getValue());
            }
            //输出子属性
            Iterator iterator = ele.elementIterator();
            while (iterator.hasNext()) {
                Element element=(Element)iterator.next();
                System.out.println(element.getName()+":"+element.getTextTrim());
            }
        }

 八、Jackson,Json解析

maven依赖:

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.5</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.9.5</version>
        </dependency>

 

主类:

ObjectMapper mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        //生成对象
        Pojo pojo2String = new Pojo();
        pojo2String.setPojoId(123);
        pojo2String.setPojoName(456);
        ArrayList<Phone> phones = new ArrayList<>();
        phones.add(new Phone("手机", "phone"));
        phones.add(new Iphone("苹果", "iphone", "siri", "store", "1"));
        phones.add(new Xphone("小米", "xphone", "xiaoai", "store", "2"));
        pojo2String.setPhoneList(phones);
        //将对象转化为Json
        System.out.println(mapper.writeValueAsString(pojo2String));
        //将Json转化为对象
        String message = "{\"pojoId\":123,\"pojoName\":456,\"pojoPw\":0,\"list\":null,\"phoneList\":[{\"name\":\"手机\",\"type\":\"phone\"},{\"name\":\"苹果\",\"type\":\"iphone\",\"siRi\":\"siri\",\"appStore\":\"store\",\"id\":\"1\"},{\"name\":\"小米\",\"type\":\"xphone\",\"id\":\"2\",\"xiaomiStore\":\"store\",\"xiaoai\":\"xiaoai\"}]}";
        /*在有继承关系时可以在父类中添加注解,根据字段的内容生成对应的子类对象,详见注解*/
        Pojo String2Pojo = mapper.readValue(message, Pojo.class);
        System.out.println(String2Pojo.getPhoneList());

注解:

@JsonIgnoreProperties

这是一个类注解,可以标记多个属性让Jackson忽略。

@JsonIgnoreProperties({ "id" })
@JsonIgnoreProperties(ignoreUnknown = true)
public class BeanWithIgnore { public int id; public String name; }

•参数ignoreUnknowntrue时, Json字符串如果有未知的属性名, 则不会抛出异常

@JsonIgnore

该注解用于属性级别, 用于标明一个属性可以被Jackson忽略

public class BeanWithIgnore {
    @JsonIgnore
    public int id;
 
    public String name;
}

@JsonIgnoreType

必须作用于类, 标明以该类为类型的属性都会被Jackson忽略(必须是属性,例如LIst中的泛型为该类则不会被忽略)

public class User {
    public int id;
    public Name name;
 
    @JsonIgnoreType
    public static class Name {
        public String firstName;
        public String lastName;
    }
}

@JsonInclude(JsonInclude.Include.NON_NULL)

作用于类上,被标注后字段为null时则不会输出该字段

@JsonInclude(Include.NON_NULL)
public class MyBean {
    public int id;
    public String name;
}

@JsonProperty("HQ")

@JsonProperty("HQ")   //java属性headquarters序列化到json字段的名称为HQ
private String headquarters;

@JsonTypeInfo和@JsonSubTypes

俩注解搭配使用可以解决反序列化中多态问题,即根据Json字符串中某个属性的值生成对应的子类

比如:{"className":"bean.Phone","name":"手机","type":"phone"},

{"className":"bean.Iphone","name":"苹果","type":"iphone","siRi":"siri","appStore":"store","id":"1"},

{"className":"bean.Xphone","name":"小米","type":"xphone","id":"2","xiaomiStore":"store","xiaoai":"xiaoai"}

解析时会根据id=1生成Iphone类,id=2生成Xphone类,默认Phone。

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "id", visible = true, defaultImpl = Phone.class)
@JsonSubTypes({@JsonSubTypes.Type(name = "1", value = Iphone.class),
        @Type(name = "2", value = Xphone.class)
})
public class Phone {}

 九、Mina框架

角色:服务器端、客户端

主要代码:

服务器端:

public class ClientReceived {
    public static void main(String[] args) {
        try {
            //建立对象
            NioSocketAcceptor acceptor = new NioSocketAcceptor();
            //设置过滤器,添加解析
            acceptor.getFilterChain().addLast("protocol", new ProtocolCodecFilter(new MyCodecFactory(new MyEncode(), new MyDecode())));
//            acceptor.getSessionConfig().setReadBufferSize(2048);
//            acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
            //设置Handler
            acceptor.setHandler(new MyIoHandler());
            //绑定端口
            acceptor.bind(new InetSocketAddress(7317));
            System.out.println("程序启动,等待链接");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 

客户端:

public class ClientWriter {
    public static void main(String[] args) throws InterruptedException {
        // 创建客户端连接
        IoConnector connector = new NioSocketConnector();
        // 增加编码过滤器,统一编码UTF-8
        connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new PrefixedStringCodecFactory(Charset.forName("UTF-8"))));
        // 设置客户端逻辑处理器
        connector.setHandler(new MyIoHandler());
        // 连接
        ConnectFuture connectFuture = connector.connect(new InetSocketAddress("10.1.112.134", 7317));
        // 等待建立连接
        connectFuture.awaitUninterruptibly(30000);
        // 获取连接会话
        IoSession session = connectFuture.getSession();
        System.out.println("客户端内容输入:");
        String[] messages = "12 34 68 96".split(" ");
        byte[] reply = new byte[messages.length];
        for (int i = 0; i < messages.length; i++) {
            reply[i] = (byte) ((Integer.parseInt(messages[i])) & 0xFF);
        }
        AbstractIoBuffer buffer = (AbstractIoBuffer) AbstractIoBuffer.allocate(reply.length, false);
        buffer.put(reply);
        buffer.flip();
        while (true) {
            Thread.sleep(5000);
            session.write(buffer);
        }
    }
}
Handler:
public class MyIoHandler extends IoHandlerAdapter {
    @Override
    public void sessionCreated(IoSession session) throws Exception {
        super.sessionCreated(session);
    }

    @Override
    public void sessionOpened(IoSession session) throws Exception {
        System.out.println("成功连接到" + session.getId());
        super.sessionOpened(session);
    }

    @Override
    public void sessionClosed(IoSession session) throws Exception {
        System.out.println("链接关闭" + session.getId());
        super.sessionClosed(session);
    }

    @Override
    public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
        super.sessionIdle(session, status);
    }

    @Override
    public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
        System.out.println("异常捕获");
        cause.printStackTrace();
        super.exceptionCaught(session, cause);
    }

    @Override
    public void messageReceived(IoSession session, Object message) throws Exception {
        byte[] buffer = (byte[]) message;
        System.out.print("接收到message");
        for (byte b : buffer) {
            Integer integer = Integer.valueOf(b);
            String value = integer.toHexString(integer).replace("ffffff", "");
            if (value.length() == 1) {
                value = "0" + value;
            }
            System.out.print(value + " ");
        }
        byte[] bytes = {02, 03};
        session.write(bytes);
        System.out.print("\n不解密");
        for(byte b : buffer){
            System.out.print(b+" ");
        }
        System.out.println();

    }

    @Override
    public void messageSent(IoSession session, Object message) throws Exception {
        System.out.println("发送消息");
        super.messageSent(session, message);
    }
}

加密解密工厂:

public class MyCodecFactory implements ProtocolCodecFactory {
    private ProtocolEncoder encoder;

    private ProtocolDecoder decoder;

    public MyCodecFactory(ProtocolEncoder encoder, ProtocolDecoder decoder) {
        this.encoder = encoder;
        this.decoder = decoder;
    }

    @Override
    public ProtocolEncoder getEncoder(IoSession ioSession) throws Exception {
        return encoder;
    }

    @Override
    public ProtocolDecoder getDecoder(IoSession ioSession) throws Exception {
        return decoder;
    }
}

 

加密:

public class MyEncode extends ProtocolEncoderAdapter {
    @Override
    public void encode(IoSession ioSession, Object message, ProtocolEncoderOutput out) throws Exception {
        byte[] reply = (byte[]) message;
        AbstractIoBuffer buffer = (AbstractIoBuffer) AbstractIoBuffer.allocate(
                reply.length, false);
        buffer.put(reply);
        buffer.flip();
        out.write(buffer);
    }
}

 

解密:

public class MyDecode extends CumulativeProtocolDecoder {
    @Override
    protected boolean doDecode(IoSession ioSession, IoBuffer in, ProtocolDecoderOutput out) {
        int recvLen = in.remaining();
        if (recvLen < 1)
            return false;
        byte[] buffer = new byte[recvLen];
        in.get(buffer);
        out.write(buffer);
        return false;
    }
}

 

A、一致性哈希算法+哈希槽分区算法

一致性哈希算法

优点:增减节点时无需对所有的数据再算一遍哈希散落,只需要对新增节点的下个节点上的数据计算即可

缺点:数据倾斜

该方法适用于多节点映射,A始终映射1,B始终映射2,当A节点离线后1寻找其他节点映射。

public class NodeReal extends Thread {
    private static int virNodesNum = 150;
    //key:node  value:hash
    private Map<String, List<Integer>> realNodeToVirNodesHashCode = new ConcurrentHashMap<>();
    //key:hash  value:node
    private SortedMap<Integer, String> ring = new TreeMap<>();

    public synchronized void addNode(String node) {
        if (realNodeToVirNodesHashCode.containsKey(node)) {
            return;
        }
        // 创建虚拟节点,并放置到环上去
        // 虚拟节点的hashcode 放入到 realNodeToVirNodesHashCode 中
        int hash;
        List<Integer> hashCodes = new ArrayList<>();
        for (int i = 0; i < virNodesNum; i++) {
            hash = rehash(node + "---" + i);
            ring.putIfAbsent(hash, node);
            hashCodes.add(hash);
        }
        realNodeToVirNodesHashCode.put(node, hashCodes);
    }

    public String getNode(String key) {
        int hash = rehash(key);
        // 从环上选择一个顺时针方向
        // (升序方向--或者降序方向都可,这里升序)的
        // 第一个虚拟节点作为目标节点返回
        SortedMap<Integer, String> tailMap = ring.tailMap(hash); // tailMap中的所有key值>=hash
        return tailMap.isEmpty() ? ring.get(ring.firstKey()) : tailMap.get(tailMap.firstKey());
    }

    private static int rehash(Object o) {
        int hash = o.hashCode();
        hash *= 16777619;// 32 bit FNV_prime = 2^24 + 2^8 + 0x93 = 16777619
        return Math.abs(hash ^ (hash >>> 16));
    }
}

 

使用:

public static void main(String[] args) {
        NodeReal nodeReal = new NodeReal();
        int lang = 25;
        String[] terminals = new String[lang];
        for (int i = 1; i <= lang; i++) {
            terminals[i - 1] = "1000010" + i;
        }
        nodeReal.addNode("fcu_1");
        nodeReal.addNode("fcu_2");
        nodeReal.addNode("fcu_3");
        nodeReal.addNode("fcu_4");
        nodeReal.addNode("fcu_5");
        LinkedHashMap<String, String> relaMapTmp = new LinkedHashMap<>();
        for (int i = 0; i < terminals.length; i++) {
            String terminalId = terminals[i];
            String node = nodeReal.getNode(terminalId);
            relaMapTmp.put(terminalId, node);
        }
        relaMapTmp.forEach((k, v) -> {
            System.out.println("termianId:" + k + ",fcu:" + v);
        });
    }

 

哈希槽分区算法

将适用的算法获取hash值,将hash值取余散列到对应的槽位上,而所有的节点会平均分配槽位。

当增加或者删除节点时,会将槽位分配到其他节点 或者 将其他节点槽位分配给新增的节点,保证所有所持槽位被平均分配。

同时槽点上的数据会随之迁移到对应节点上去

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class HashSlotPartitioner {
    private final int numSlots;
    private final Map<Integer, String> slotToNodeMap;
    private final List<String> nodes;

    public HashSlotPartitioner(int numSlots) {
        this.numSlots = numSlots;
        this.slotToNodeMap = new HashMap<>();
        this.nodes = new ArrayList<>();
    }

    public void addNode(String nodeName) {
        nodes.add(nodeName);
        reassignSlots();
    }

    public void removeNode(String nodeName) {
        nodes.remove(nodeName);
        reassignSlots();
    }

    public void reassignSlots() {
        slotToNodeMap.clear();
        int slotsPerNode = numSlots / nodes.size();
        for (int i = 0; i < nodes.size(); i++) {
            String node = nodes.get(i);
            for (int slotIndex = i * slotsPerNode; slotIndex < (i + 1) * slotsPerNode; slotIndex++) {
                String slotKey = "slot-" + slotIndex;
                slotToNodeMap.put(slotKey.hashCode(), node);
            }
        }
    }

    public String getNodeForKey(String key) {
        int slotIndex = key.hashCode() % numSlots;
        String slotKey = "slot-" + slotIndex;
        return slotToNodeMap.get(slotKey.hashCode());
    }
}

 

B、RMI

1、建立接口继承Remote类

public interface UserService extends Remote {
    User findUser(String userId) throws RemoteException;
}

2、实现接口,重写方法

public class UserServiceImpl extends UnicastRemoteObject implements UserService {
    protected UserServiceImpl() throws RemoteException {
    }

    @Override
    public User findUser(String userId) throws RemoteException {
        return  new User("1","wgy");
    }

    public User findUser2(String userId) throws RemoteException {
        return  new User(userId,"wgy");
    }
}

3、服务器端

public class RmiServer {
    public static void main(String[] args) {
        try {
            UserService userService = new UserServiceImpl();
            LocateRegistry.createRegistry(1900);
            Naming.rebind("//localhost:1900/user", userService);
            Naming.rebind("//localhost:1900/user1", userService);
            Naming.rebind("//localhost:1900/user2", userService);
            System.out.println("start server,port is 1900");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

4、客户端

public class RmiClient {
    public static void main(String args[]) {
        User answer;
        String userId = "00001";
        try {
            UserService access = (UserService) Naming.lookup("rmi://localhost:1900/user2");
            answer = access.findUser(userId);
            System.out.println("query:" + userId);
            System.out.println("result:" + answer.toString());
        } catch (Exception ae) {
            System.out.println(ae);
        }
    }
}

 

C、布隆过滤器

依赖:

        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>29.0-jre</version>
        </dependency>

代码:

public class BloomTest {
    /**
     * 预计插入的数据
     */
    private static Integer expectedInsertions = 100;
    /**
     * 误判率
     */
    private static Double fpp = 0.9;
    /**
     * 布隆过滤器
     */
    private static BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(), expectedInsertions, fpp);

    public static void main(String[] args) {
        // 插入 数据
        for (int i = 0; i < expectedInsertions; i++) {
            bloomFilter.put(i);
        }
        //测试误判率
        int count = 0;
        for (int i = expectedInsertions; i < expectedInsertions * 3; i++) {
            if (bloomFilter.mightContain(i)) {
                count++;
            }
        }
        System.out.println("count:" + count);
    }
}

注:布隆过滤器判断不存在一定不存在,判断存在可能不存在

D、Nacos

依赖:

        <dependency>
            <groupId>com.alibaba.nacos</groupId>
            <artifactId>nacos-client</artifactId>
            <version>1.1.1</version>
        </dependency>

代码:

public class MyNacos {
    public static void main(String[] args) throws Exception {
        Properties properties = new Properties();
        properties.put("serverAddr","127.0.0.1:8848");

        ConfigService configService = NacosFactory.createConfigService(properties);

        String content = configService.getConfig("kafka","myGroup",2000);
        System.out.println(content);
    }
}

 

posted @ 2020-11-23 21:42  王啦啦  阅读(104)  评论(0)    收藏  举报