首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >看老夫,如何带你操刀重构ChatGLM-SDK!

看老夫,如何带你操刀重构ChatGLM-SDK!

作者头像
小傅哥
发布于 2024-01-23 11:03:44
发布于 2024-01-23 11:03:44
60400
代码可运行
举报
运行总次数:0
代码可运行

作者:小傅哥 博客:https://bugstack.cn

❝沉淀、分享、成长,让自己和他人都能有所收获!😜 ❞

大家好,我是技术UP主小傅哥。

鉴于智谱AI发布了最新一代 GLM3.0GLM4.0 基座大模型,我又要对自己开发的这款开源 chatglm-sdk-java 进行改造了!因为需要做新老接口的模型调用中数据格式兼容,这将是一场编码设计复杂场景的对抗挑战。💐 请看小傅哥如何操刀改造!

为什么改造SDK会比较复杂?🤔

通常来说,我们开发好一款SDK后,就会投入到项目中使用,而使用的方式会根据SDK的出入参标准进行对接。比如一个接口的入参原本有2个参数,A StringB String 类型,但现在因为有额外的功能添加,从2个参数调整为3个参数,同时需要对原本的 B 参数 String 类型,扩展为 Object 类型,添加更多的属性信息。同时出参也有对应响应结构变化。

那么对于这种线上正在使用又需要改造代码的情况,我们不可能把原有的代码都铲了不要,所以需要做一些优雅的兼容的开发处理。让工程更加好维护、好迭代。

在设计原则和设计模式的锤炼下,写出高质量的代码。

那么,接下来小傅哥就带着大家讲讲这段关于GLM新增模型后 SDK 的重构操作。

文末有整个 SDK 的源码,直接免费获取,拿过去就是嘎嘎学习!

一、需求场景

智谱AI文档:https://open.bigmodel.cn/overview

本次文档中新增加了 GLM-3-Turbo、GLM-4、GLM-4v、cogview,这样四个新模型,与原来的旧版 chatGLM_6b_SSE、chatglm_lite、chatglm_lite_32k、chatglm_std、chatglm_pro,在接口调用上做了不小的修改。因为新版的模型增加了如插件「联网、知识库、函数库」、画图、图片识别这样的能力,所以出入参也有相应的变化。

1. curl 旧版

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
curl -X POST \
        -H "Authorization: Bearer BearerTokenUtils.getToken(获取)" \
        -H "Content-Type: application/json" \
        -H "Accept: text/event-stream" \
        -d '{
              "top_p": 0.7,
              "sseFormat": "data",
              "temperature": 0.9,
              "incremental": true,
              "request_id": "xfg-1696992276607",
              "prompt": [
                  {
                  "role": "user",
                  "content": "写个java冒泡排序"
                  }
              ]
            }' \
  http://open.bigmodel.cn/api/paas/v3/model-api/chatglm_lite/sse-invoke
  • 注意:旧版的调用方式是把模型放到接口请求中,如;chatglm_lite 就是放到请求地址中。

2. curl 3&4

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
curl -X POST \
        -H "Authorization: Bearer BearerTokenUtils.getToken(获取)" \
        -H "Content-Type: application/json" \
        -d '{
          "model":"glm-3-turbo",
          "stream": "true",
          "messages": [
              {
                  "role": "user",
                  "content": "写个java冒泡排序"
              }
          ]
        }' \
  https://open.bigmodel.cn/api/paas/v4/chat/completions
  • 注意:新版的模型为入参方式调用,接口是统一的接口。此外入参格式的流式可以通过参数 "stream": "true" 控制。

3. curl 4v

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
curl -X POST \
        -H "Authorization: Bearer BearerTokenUtils.getToken(获取)" \
        -H "Content-Type: application/json" \
        -d '{
                "messages": [
                    {
                        "role": "user",
                        "content": [
                          {
                            "type": "text",
                            "text": "这是什么图片"
                          },
                          {
                            "type": "image_url",
                            "image_url": {
                              "url" : "支持base64和图片地址;https://bugstack.cn/images/article/project/chatgpt/chatgpt-extra-231011-01.png"
                            }
                          }
                        ]
                    }
                ],
                "model": "glm-4v",
                "stream": "true"
            }' \
  https://open.bigmodel.cn/api/paas/v4/chat/completions
  • 注意:多模态4v模型,content 字符串升级为对象。这部分与 chatgpt 的参数结构是一致的。所以我们在开发这部分功能的时候,也需要做兼容处理。因为本身它既可以支持对象也可以支持 conten 为字符串。

4. curl cogview

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
curl -X POST \
        -H "Authorization: Bearer BearerTokenUtils.getToken(获取)" \
        -H "Content-Type: application/json" \
        -d '{
          "model":"cogview-3",
          "prompt":"画一个小狗狗"
        }' \
  https://open.bigmodel.cn/api/paas/v4/images/generations
  • 注意:图片的文生图是一个新的功能,旧版没有这个接口。所以开发的时候按照独立的接口开发即可。

综上,这些接口开发还需要注意;

  1. 首先,小傅哥根据官网文档编写了对应的 curl 请求格式。方便开发时可以参考和验证。
  2. 之后,curl 旧版是文本类处理,curl 3&4 是新版的文档处理。两个可以对比看出,旧版的入参是 prompt,新版是 messages
  3. 另外,本次API文档新增加了文生图,和4v(vision)多模态的图片识别。

接下来,我们就要来设计怎么在旧版的SDK中兼容这些功能实现。

二、功能实现

1. 调用流程

如图,是整个本次 SDK 的实现的核心流程,其中执行器部分是本次重点开发的内容。在旧版的 SDK 中是直接从会话请求进入模型的调用,没有执行器的添加。而执行器的引入则是为了解耦调用过程,依照于不同的请求模型(chatglm_std、chatglm_pro、GLM_4...),可以调用到不同的执行器上去。

2. 执行器「解耦」

2.1 接口
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface Executor {

    /**
     * 问答模式,流式反馈
     *
     * @param chatCompletionRequest 请求信息
     * @param eventSourceListener   实现监听;通过监听的 onEvent 方法接收数据
     * @return 应答结果
     * @throws Exception 异常
     */
    EventSource completions(ChatCompletionRequest chatCompletionRequest, EventSourceListener eventSourceListener) throws Exception;
    
    // ... 省略部分接口
}    
2.2 旧版
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class GLMOldExecutor implements Executor {

    /**
     * OpenAi 接口
     */
    private final Configuration configuration;
    /**
     * 工厂事件
     */
    private final EventSource.Factory factory;

    public GLMOldExecutor(Configuration configuration) {
        this.configuration = configuration;
        this.factory = configuration.createRequestFactory();
    }

    @Override
    public EventSource completions(ChatCompletionRequest chatCompletionRequest, EventSourceListener eventSourceListener) throws Exception {
        // 构建请求信息
        Request request = new Request.Builder()
                .url(configuration.getApiHost().concat(IOpenAiApi.v3_completions).replace("{model}", chatCompletionRequest.getModel().getCode()))
                .post(RequestBody.create(MediaType.parse("application/json"), chatCompletionRequest.toString()))
                .build();

        // 返回事件结果
        return factory.newEventSource(request, eventSourceListener);
    }
    
    // ... 省略部分接口
    
}    
2.3 新版
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class GLMExecutor implements Executor, ResultHandler {

    /**
     * OpenAi 接口
     */
    private final Configuration configuration;
    /**
     * 工厂事件
     */
    private final EventSource.Factory factory;
    /**
     * 统一接口
     */
    private IOpenAiApi openAiApi;

    private OkHttpClient okHttpClient;

    public GLMExecutor(Configuration configuration) {
        this.configuration = configuration;
        this.factory = configuration.createRequestFactory();
        this.openAiApi = configuration.getOpenAiApi();
        this.okHttpClient = configuration.getOkHttpClient();
    }

    @Override
    public EventSource completions(ChatCompletionRequest chatCompletionRequest, EventSourceListener eventSourceListener) throws Exception {
        // 构建请求信息
        Request request = new Request.Builder()
                .url(configuration.getApiHost().concat(IOpenAiApi.v4))
                .post(RequestBody.create(MediaType.parse(Configuration.JSON_CONTENT_TYPE), chatCompletionRequest.toString()))
                .build();

        // 返回事件结果
        return factory.newEventSource(request, chatCompletionRequest.getIsCompatible() ? eventSourceListener(eventSourceListener) : eventSourceListener);
    }

    
    // ... 省略部分接口
    
}    

在新版的执行实现中,除了 IOpenAiApi.v4 接口的变动,还有一块是对外结果的封装处理。这是因为在旧版的接口对接中使用的是 EventType「add、finish、error、interrupted」枚举来判断。但在新版中则只是判断 stop 标记符。所以为了让之前的SDK使用用户更少的改动代码,这里做了结果的封装。

3. 注入配置

源码:cn.bugstack.chatglm.session.Configuration

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public HashMap<Model, Executor> newExecutorGroup() {
    this.executorGroup = new HashMap<>();
    // 旧版模型,兼容
    Executor glmOldExecutor = new GLMOldExecutor(this);
    this.executorGroup.put(Model.CHATGLM_6B_SSE, glmOldExecutor);
    this.executorGroup.put(Model.CHATGLM_LITE, glmOldExecutor);
    this.executorGroup.put(Model.CHATGLM_LITE_32K, glmOldExecutor);
    this.executorGroup.put(Model.CHATGLM_STD, glmOldExecutor);
    this.executorGroup.put(Model.CHATGLM_PRO, glmOldExecutor);
    this.executorGroup.put(Model.CHATGLM_TURBO, glmOldExecutor);
    // 新版模型,配置
    Executor glmExecutor = new GLMExecutor(this);
    this.executorGroup.put(Model.GLM_3_5_TURBO, glmExecutor);
    this.executorGroup.put(Model.GLM_4, glmExecutor);
    this.executorGroup.put(Model.GLM_4V, glmExecutor);
    this.executorGroup.put(Model.COGVIEW_3, glmExecutor);
    return this.executorGroup;
}
  • 对于不同的模型,走哪个执行器,在 Configuration 配置文件中写了这样的配置信息。
  • 这样当你调用 CHATGLM_TURBO 就会走到 glmOldExecutor 模型,调用 GLM_4V 就会走到 glmExecutor 模型。

4. 参数兼容

ChatCompletionRequest 作为一个重要的应答参数对象,在本次的接口变化中也是调整了不少字段。但好在小傅哥之前就提供了一个 toString 对象的方法。在这里我们可以做不同类型参数的处理。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public String toString() {
    try {
        // 24年1月发布新模型后调整
        if (Model.GLM_3_5_TURBO.equals(this.model) || Model.GLM_4.equals(this.model) || Model.GLM_4V.equals(this.model)) {
            Map<String, Object> paramsMap = new HashMap<>();
            paramsMap.put("model", this.model.getCode());
            if (null == this.messages && null == this.prompt) {
                throw new RuntimeException("One of messages or prompt must not be empty!");
            }
            paramsMap.put("messages", this.messages != null ? this.messages : this.prompt);
            if (null != this.requestId) {
                paramsMap.put("request_id", this.requestId);
            }
            if (null != this.doSample) {
                paramsMap.put("do_sample", this.doSample);
            }
            paramsMap.put("stream", this.stream);
            paramsMap.put("temperature", this.temperature);
            paramsMap.put("top_p", this.topP);
            paramsMap.put("max_tokens", this.maxTokens);
            if (null != this.stop && this.stop.size() > 0) {
                paramsMap.put("stop", this.stop);
            }
            if (null != this.tools && this.tools.size() > 0) {
                paramsMap.put("tools", this.tools);
                paramsMap.put("tool_choice", this.toolChoice);
            }
            return new ObjectMapper().writeValueAsString(paramsMap);
        }
        
        // 默认
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("request_id", requestId);
        paramsMap.put("prompt", prompt);
        paramsMap.put("incremental", incremental);
        paramsMap.put("temperature", temperature);
        paramsMap.put("top_p", topP);
        paramsMap.put("sseFormat", sseFormat);
        return new ObjectMapper().writeValueAsString(paramsMap);
    } catch (JsonProcessingException e) {
        throw new RuntimeException(e);
    }
}
  • 如果为本次调整的新增模型,则走新的方式装配参数信息。
  • 通过这样的方式可以很轻松的把以前叫做 prompt 的字段调整为 messages 名称。类似的操作可以看具体的代码。关于字段的出入参处理,但比较同类,就不一一列举了

三、功能验证

注意:测试前需要申请ApiKey https://open.bigmodel.cn/overview 有非常多的免费额度。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Before
public void test_OpenAiSessionFactory() {
    // 1. 配置文件
    Configuration configuration = new Configuration();
    configuration.setApiHost("https://open.bigmodel.cn/");
    configuration.setApiSecretKey("62ddec38b1d0b9a7b0fddaf271e6ed90.HpD0SUBUlvqd05ey");
    configuration.setLevel(HttpLoggingInterceptor.Level.BODY);
    // 2. 会话工厂
    OpenAiSessionFactory factory = new DefaultOpenAiSessionFactory(configuration);
    // 3. 开启会话
    this.openAiSession = factory.openSession();
}
  • 申请后把你的 ApiKey 替换 setApiSecretKey 就可以使用了。

1. 文生文「支持联网」

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Test
public void test_completions() throws Exception {
    CountDownLatch countDownLatch = new CountDownLatch(1);
    // 入参;模型、请求信息
    ChatCompletionRequest request = new ChatCompletionRequest();
    request.setModel(Model.GLM_3_5_TURBO); // chatGLM_6b_SSE、chatglm_lite、chatglm_lite_32k、chatglm_std、chatglm_pro
    request.setIncremental(false);
    request.setIsCompatible(true); // 是否对返回结果数据做兼容,24年1月发布的 GLM_3_5_TURBO、GLM_4 模型,与之前的模型在返回结果上有差异。开启 true 可以做兼容。
    // 24年1月发布的 glm-3-turbo、glm-4 支持函数、知识库、联网功能
    request.setTools(new ArrayList<ChatCompletionRequest.Tool>() {
        private static final long serialVersionUID = -7988151926241837899L;
        {
            add(ChatCompletionRequest.Tool.builder()
                    .type(ChatCompletionRequest.Tool.Type.web_search)
                    .webSearch(ChatCompletionRequest.Tool.WebSearch.builder().enable(true).searchQuery("小傅哥").build())
                    .build());
        }
    });
    request.setPrompt(new ArrayList<ChatCompletionRequest.Prompt>() {
        private static final long serialVersionUID = -7988151926241837899L;
        {
            add(ChatCompletionRequest.Prompt.builder()
                    .role(Role.user.getCode())
                    .content("小傅哥的是谁")
                    .build());
        }
    });
    // 请求
    openAiSession.completions(request, new EventSourceListener() {
        @Override
        public void onEvent(EventSource eventSource, @Nullable String id, @Nullable String type, String data) {
            ChatCompletionResponse response = JSON.parseObject(data, ChatCompletionResponse.class);
            log.info("测试结果 onEvent:{}", response.getData());
            // type 消息类型,add 增量,finish 结束,error 错误,interrupted 中断
            if (EventType.finish.getCode().equals(type)) {
                ChatCompletionResponse.Meta meta = JSON.parseObject(response.getMeta(), ChatCompletionResponse.Meta.class);
                log.info("[输出结束] Tokens {}", JSON.toJSONString(meta));
            }
        }
        @Override
        public void onClosed(EventSource eventSource) {
            log.info("对话完成");
            countDownLatch.countDown();
        }
        @Override
        public void onFailure(EventSource eventSource, @Nullable Throwable t, @Nullable Response response) {
            log.info("对话异常");
            countDownLatch.countDown();
        }
    });
    // 等待
    countDownLatch.await();
}

2. 文生图

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Test
public void test_genImages() throws Exception {
    ImageCompletionRequest request = new ImageCompletionRequest();
    request.setModel(Model.COGVIEW_3);
    request.setPrompt("画个小狗");
    ImageCompletionResponse response = openAiSession.genImages(request);
    log.info("测试结果:{}", JSON.toJSONString(response));
}

3. 多模态

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void test_completions_v4() throws Exception {
    CountDownLatch countDownLatch = new CountDownLatch(1);
    // 入参;模型、请求信息
    ChatCompletionRequest request = new ChatCompletionRequest();
    request.setModel(Model.GLM_4V); // GLM_3_5_TURBO、GLM_4
    request.setStream(true);
    request.setMessages(new ArrayList<ChatCompletionRequest.Prompt>() {
        private static final long serialVersionUID = -7988151926241837899L;
        {
            // content 字符串格式
            add(ChatCompletionRequest.Prompt.builder()
                    .role(Role.user.getCode())
                    .content("这个图片写了什么")
                    .build());
            // content 对象格式
            add(ChatCompletionRequest.Prompt.builder()
                    .role(Role.user.getCode())
                    .content(ChatCompletionRequest.Prompt.Content.builder()
                            .type(ChatCompletionRequest.Prompt.Content.Type.text.getCode())
                            .text("这是什么图片")
                            .build())
                    .build());
            // content 对象格式,上传图片;图片支持url、basde64
            add(ChatCompletionRequest.Prompt.builder()
                    .role(Role.user.getCode())
                    .content(ChatCompletionRequest.Prompt.Content.builder()
                            .type(ChatCompletionRequest.Prompt.Content.Type.image_url.getCode())
                            .imageUrl(ChatCompletionRequest.Prompt.Content.ImageUrl.builder().url("https://bugstack.cn/images/article/project/chatgpt/chatgpt-extra-231011-01.png").buil
                            .build())
                    .build());
        }
    });
    openAiSession.completions(request, new EventSourceListener() {
        @Override
        public void onEvent(EventSource eventSource, @Nullable String id, @Nullable String type, String data) {
            if ("[DONE]".equals(data)) {
                log.info("[输出结束] Tokens {}", JSON.toJSONString(data));
                return;
            }
            ChatCompletionResponse response = JSON.parseObject(data, ChatCompletionResponse.class);
            log.info("测试结果:{}", JSON.toJSONString(response));
        }
        @Override
        public void onClosed(EventSource eventSource) {
            log.info("对话完成");
            countDownLatch.countDown();
        }
        @Override
        public void onFailure(EventSource eventSource, @Nullable Throwable t, @Nullable Response response) {
            log.error("对话失败", t);
            countDownLatch.countDown();
        }
    });
    // 等待
    countDownLatch.await();
}

四、工程源码

  • 申请ApiKey:https://open.bigmodel.cn/usercenter/apikeys - 注册申请开通,即可获得 ApiKey
  • 运行环境:JDK 1.8+
  • 支持模型:chatGLM_6b_SSE、chatglm_lite、chatglm_lite_32k、chatglm_std、chatglm_pro、chatglm_turbo、glm-3-turbo、glm-4、glm-4v、cogview-3
  • maven pom - 已发布到Maven仓库
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<dependency>
    <groupId>cn.bugstack</groupId>
    <artifactId>chatglm-sdk-java</artifactId>
    <version>2.0</version>
</dependency>
  • 源码(Github):https://github.com/fuzhengwei/chatglm-sdk-java
  • 源码(Gitee):https://gitee.com/fustack/chatglm-sdk-java
  • 源码(Gitcode):https://gitcode.net/KnowledgePlanet/road-map/chatglm-sdk-java
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-01-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 bugstack虫洞栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
Mina入门实例
继续上一篇,这篇主要讲通过mina往B端发送消息。并接受消息,mina是一个网络通信框架,封装了javaNIO。简单易用。网上有非常多关于他的介绍,在此不赘述了。
全栈程序员站长
2022/07/10
5780
Apache MINA框架「建议收藏」
Apache MINA(Multipurpose Infrastructure for Network Applications) 是 Apache 组织一个较新的项目,它为开发高性能和高可用性的网络应用程序提供了非常便利的框架。当前发行的 MINA 版本支持基于 Java NIO 技术的 TCP/UDP 应用程序开发、串口通讯程序(只在最新的预览版中提供),MINA 所支持的功能也在进一步的扩展中。目前正在使用 MINA 的软件包括有:Apache Directory Project、AsyncWeb、AMQP(Advanced Message Queuing Protocol)、RED5 Server(Macromedia Flash Media RTMP)、ObjectRADIUS、Openfire 等等。
全栈程序员站长
2022/07/25
9240
Apache MINA框架「建议收藏」
使用mina解析http协议的使用
在使用mina的过程中,我们通常会自定义各种报文,以使用于自己的业务。今天就为大家带来一款类似http协议的解码过程。 mina有自带的解析http数据包的解码类。可以使用maven配置一下内容获取源码:
业余草
2019/01/21
1.2K0
java使用mina和websocket通信
这里以mina整合springMVC为例: //springMVC的配置: <!-- mina --> <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer"> <property name="customEditors"> <map> <!-- spring升级后此配置已失效 会报错 <entry key="java.net.SocketAddr
用户1215919
2018/02/27
4.5K1
用MINA实现UDP通信的例子
Apache Mina Server 是一个网络通信应用框架,也就是说,它主要是对基于TCP/IP、UDP/IP协议栈的通信框架(当然,也可以提供JAVA 对象的序列化服务、虚拟机管道通信服务等),Mina 可以帮助我们快速开发高性能、高扩展性的网络通信应用,Mina 提供了事件驱动、异步(Mina 的异步IO 默认使用的是JAVA NIO 作为底层支持)操作的编程模型。
麦克劳林
2018/09/11
1.6K0
Spring4.0MVC学习资料,ApplicationContext中的方法详解(三)
做为java开源的一部分,spring框架一直排在老大的位置。Spring4.0 是 Spring 推出的一个重大版本升级,进一步加强了 Spring 作为 Java 领域第一开源平台的地位。Spring4.0 引入了众多 Java 开发者期盼的新特性,如泛型依赖注入、SpEL、校验及格式化框架、Rest风格的 WEB 编程模型等。这些新功能实用性强、易用性高,可大幅降低 JavaEE 开发的难度,同时有效提升应用开发的优雅性。为了方便开发,Spring的ApplicationContext类,给我们提供了很多实用的方法,我在这里进行一下讲解。
业余草
2019/01/21
4260
Apache Mina开发手册
Apache Mina是一个网络应用框架,简化用户开发高性能、高可扩展性的网络应用程序的难度。Mina提供了一个抽象的事件驱动的异步API,通过Java NIO实现各种传输协议如TCP/IP和UDP/IP。
星哥玩云
2022/07/03
1.5K0
Apache Mina开发手册
java mina框架实例_MINA框架简介和一个简单的例子
MINA(Multipurpose Infrastructure for Network Applications)是用于开发高性能和高可用性的网络应用程序的基础框架。通过使用MINA框架可以可以省下处理底层I/O和线程并发等复杂工作,开发人员能够把更多的精力投入到业务设计和开发当中。MINA框架的应用比较广泛,应用的开源项目有Apache Directory、AsyncWeb、Apache Qpid、QuickFIX/J、Openfire、SubEthaSTMP、red5等。MINA框架当前稳定版本是1.1.6,最新的2.0版本目前已经发布了M1版本。
全栈程序员站长
2022/07/25
1.5K0
NIO框架Mina学习
前言: 找了篇文章看了看,nio框架数Mina用的最多! 代码: 服务端: package com.mina; import java.net.InetSocketAddress; import java.nio.charset.Charset; import org.apache.mina.core.service.IoAcceptor; import org.apache.mina.core.session.IdleStatus; import org.apache.mina.filte
JQ实验室
2022/02/09
5940
Spring4.0MVC学习资料,简单学习教程(一)
Spring框架的核心部分就是Ioc容器,而Ioc控制的就是各种Bean,一个Spring项目的水平往往从其XML配置文件内容就能略知一二,很多项目,往往是外包公司的项目,配置文件往往是乱七八糟,抱着能跑就行,不报错就行的态度去写,然后在项目中后期发现各种缺失又去一通乱补,其结果就是,整个文档可读性极差,毫无章法。这也不能怪写这个XML的人,拿着苦逼程序员的工资干着架构师的工作必然是这个结果。为了程序员的幸福,我认为有必要来一套简单快速的官方文档核心配置归纳整理和解释,好让苦逼猿们在工作中能正确快速的提高自身和项目的整体水平。
业余草
2019/01/21
3970
Spring4.0MVC学习资料,简单学习教程(一)
Mina框架的使用[通俗易懂]
每建立一个Socket连接时,同时创建一个新线程对该Socket进行单独通信(采用阻塞的方式通信)。这种方式具有很高的响应速度,并且控制起来也很简单,在连接数较少的时候非常有效,但是如果对每一个连接都产生一个线程的无疑是对系统资源的一种浪费,如果连接数较多将会出现资源不足的情况。
全栈程序员站长
2022/08/01
1.5K0
Mina框架的使用[通俗易懂]
mina框架学习
mina框架是对nio进行的一个封装,可用于java的网络编程,包括TCP/IP和UTP/IP编程,主要屏蔽了网络通信的一些细节,对socket进行封装,并且是用nio的一个实现框架,mina的主要类如下:
全栈程序员站长
2022/07/22
1.2K0
不会框架不要紧,我带你自定义框架
前言:这标题说的有点大了,当一回标题党,之前在学JSP的时候提到了JSTL和EL表达式,由于一直钟情于Servlet,迟迟没有更新别的,这回算是跳出来了。这回放个大招,用Spring+SpringMVC+Spring Jdbc Template,实现一个增删改查加分页,但重点不在这,我的重心在于JSTL和EL表达式,标题虽然有点大,但话糙理不糙,我真的是要自定义框架,当然,这个框架可大可小,大的我不敢说,用JSTL自定义标签封装个分页还是可以的,也算补上JSTL和EL表达式的学习吧。对于那些一直跟着我跟新博客脚步的朋友,我提醒你们不要着急,你要是好奇就可以先试着跟着我的案例试试手,不要看到SSM框架就说还没学,不会啥的,哈哈,开玩笑,都没学怎么可能会呢,我说了,这篇的重点在于JSTL和EL表达式,重要的话说了不下三遍了,至于附加的SSM,我会持续跟新,会手把手带你理解的,别急,别急,就当先认识一下SSM吧。
泰斗贤若如
2019/08/06
5660
不会框架不要紧,我带你自定义框架
破解md5加密的方法
我们知道md5加密是不可逆转的,但是要破解md5的加密也很简单。 网上也有很多在线的破解。既然是不可逆转的,那么网上的那些破解是怎么来的呢? 原因很简单,就是使用穷举法来进行破解。 如:我们计算出键盘上所有字符的组合的md5,将加密前后的字符串分别存入数据库中; 然后拿你的md5加密后的字符串进行查询得出加密前的字符串。这就是在线破解的奥秘。 但是这种破解方法也有局限性。如:我对单一一个字符串进行多次的md5加密,那么我们破解就要反复的进行穷举。 如果你不知道字符串被md5加密了多少次,那么就要反复的多试几次了。当然一般的网站使用的md5加密的密码不会太复杂。 我们就可以使用我今天所讲的这种方法来破解了。 1.首先我们要找出键盘上所有的字符,存入数组中,如下:
业余草
2019/01/21
4.4K0
netty案例,netty4.1基础入门篇九《自定义编码解码器,处理半包、粘包数据》
在实际应用场景里,只要是支持sokcet通信的都可以和Netty交互,比如中继器、下位机、PLC等。这些场景下就非常需要自定义编码解码器,来处理字节码传输,并控制半包、粘包以及安全问题。那么本章节我们通过实现ByteToMessageDecoder、MessageToByteEncoder来实现我们的需求。
小傅哥
2020/07/14
5320
netty案例,netty4.1基础入门篇九《自定义编码解码器,处理半包、粘包数据》
NIO框架入门(二):服务端基于MINA2的UDP双向通信Demo演示
NIO框架的流行,使得开发大并发、高性能的互联网服务端成为可能。这其中最流行的无非就是MINA和Netty了,MINA目前的主要版本是MINA2、而Netty的主要版本是Netty3和Netty4(Netty5已经被取消开发了:详见此文)。
JackJiang
2018/08/23
9080
NIO框架入门(二):服务端基于MINA2的UDP双向通信Demo演示
MINA 框架简介「建议收藏」
Apache Mina Server 是一个网络通信应用框架,也就是说,它主要是对基于TCP/IP、UDP/IP协议栈的通信框架(然,也可以提供JAVA 对象的序列化服务、虚拟机管道通信服务等),Mina 可以帮助我们快速开发高性能、高扩展性的网络通信应用,Mina 提供了事件驱动、异步(Mina 的异步IO 默认使用的是JAVA NIO 作为底层支持)操作的编程模型。Mina 主要有1.x 和2.x 两个分支,这里我们讲解最新版本2.0,如果你使用的是Mina 1.x,那么可能会有一些功能并不适用。学习本文档,需要你已掌握JAVA IO、JAVA NIO、JAVASocket、JAVA 线程及并发库(java.util.concurrent.*)的知识。
全栈程序员站长
2022/07/22
1.8K0
mybatis扩展之自定义类型处理器处理枚举类型
全局配置: <typeHandlers> <typeHandler handler="com.gong.mybatis.typeHandler.MyEnumEmpStatusTypeHandler" javaType="com.gong.mybatis.bean.EmpStatus"/> <!-- <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler"
西西嘛呦
2020/08/26
7530
mybatis扩展之自定义类型处理器处理枚举类型
SpringBoot 配置文件详解
配置文件的作用 : SpringBoot底层都给我们配置好了,但有时候我们需要修改一些默认配置。
jwangkun
2021/12/23
2900
Java XML和JSON:Java SE的文档处理 第2部分
本文中的示例将向您介绍JSON-B,JSON绑定API for Java。在快速概述和安装说明之后,我将向您展示如何使用JSON-B来序列化和反序列化Java对象,数组和集合; 如何使用JSON-B自定义序列化和反序列化; 以及如何在序列化或反序列化期间使用JSON-B适配器将源对象转换为目标对象。
银河1号
2019/05/16
3.6K0
相关推荐
Mina入门实例
更多 >
LV.1
这个人很懒,什么都没有留下~
目录
  • 一、需求场景
    • 1. curl 旧版
    • 2. curl 3&4
    • 3. curl 4v
    • 4. curl cogview
  • 二、功能实现
    • 1. 调用流程
    • 2. 执行器「解耦」
      • 2.1 接口
      • 2.2 旧版
      • 2.3 新版
    • 3. 注入配置
    • 4. 参数兼容
  • 三、功能验证
    • 1. 文生文「支持联网」
    • 2. 文生图
    • 3. 多模态
  • 四、工程源码
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档