- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
问题
非常简短:我想创建 Spring Shell,但作为 Web 应用程序。
我想创建一个 Web 应用程序(最好使用 Spring Boot),其中前端 (ReactJS) 看起来像一个终端(或 shell),后端处理输入的命令。看https://codepen.io/AndrewBarfield/pen/qEqWMq .我想为看起来像那样的东西构建一个完整的网络应用程序。
我想构建一个框架,这样我就可以在对前端/Web 应用程序结构一无所知的情况下开发后端命令。我基本上想实例化一个“终端”对象,我在其中提供某种输入流和输出流。这样我就可以根据我给定的接口(interface)和结构对该终端进行编程,而无需设置各种前端内容。
问题的一个很好的总结是:如何将所有键盘输入发送到后端,以及如何将所有输出发送到前端?
我想创建一个 Web 应用程序的原因是因为我希望它可以在线使用。
我尝试过的
我认为实现这一点的方法是使用 websockets。我使用此 ( https://developer.okta.com/blog/2018/09/25/spring-webflux-websockets-react) 教程创建了一个小型 Web 应用程序,没有安全部分。 websocket 部分几乎是合适的,我就是无法获得“输入”和“输出”流式对象。
@Controller
public class WebSocketController {
private SimpMessagingTemplate simpMessagingTemplate;
@Autowired
public WebSocketController(SimpMessagingTemplate simpMessagingTemplate) {
this.simpMessagingTemplate = simpMessagingTemplate;
}
@MessageMapping("/queue")
@SendToUser("/topic/greetings")
public Greeting greeting(HelloMessage message, @Header(name = "simpSessionId") String sessionId) throws Exception {
System.out.println(sessionId);
// Do some command parsing or whatever.
String output = "You inputted:" + HtmlUtils.htmlEscape(message.getName());
return new Greeting(output);
}
private MessageHeaders createHeaders(String sessionId) {
SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor.create(SimpMessageType.MESSAGE);
headerAccessor.setSessionId(sessionId);
return headerAccessor.getMessageHeaders();
}
现在有了这段代码,您就可以解析命令了。但是,它不保留任何“状态”。我不知道它如何与状态和 websockets 一起工作。
我看到你有这个 Spring Sessions + WebSockets ( https://docs.spring.io/spring-session/docs/current/reference/html5/guides/boot-websocket.html ),但这并不是我真正想要的。
我可以使用以下代码从后端向前端发送消息:
simpMessagingTemplate.convertAndSendToUser(sessionId, "/topic/greetings", "hey", createHeaders(sessionId));
但是,我希望我的终端能够等待来自用户的输入命令。看起来有点牵强,但有人知道如何实现吗?
我想要的东西
我基本上希望其他人对这个接口(interface)进行编程:
public interface ITerminal {
void setInputStream(Object someKindOfWrapperForTheInput);
void setOutputStream(Object someWrapperOfSimpMessagingTemplate);
void start();
}
当有人打开 Web 应用程序时,他们会得到一个专用的终端对象(因此每个用户一个连接)。无论何时有人在前端应用程序中输入命令,我都希望它被终端对象接收、处理,并将响应输出到前端。
这样做的原因
我真的很喜欢创建命令行应用程序,但我不喜欢构建前端的东西。我在一家构建 Web 应用程序的公司担任软件工程师,我主要负责编写后端程序。所有前端部分都是由其他人完成的(我很幸运!)。不过,我喜欢在家做一些项目,这看起来很酷。
如果您对如何解决这个问题有任何想法或想法,请给出答案!我对解决方案很感兴趣,使用 SpringBoot 框架不是必需的。我使用 Spring Boot 和 ReactJS 问这个问题,因为我已经用它构建了应用程序。已经弄清楚了很多,我认为这可能也存在。唯一的要求是我可以在 tomcat 服务器上使用 Java 实现这一点。其余的是可选的:)
不清楚?
我尽力使我的故事清晰,但我不确定我想要实现的目的是否明确。但是,我不知道如何以您理解的方式来表述它。如果您有任何建议或问题,请随时发表评论!
最佳答案
如果您唯一想要的是一个在浏览器中显示的 Live Spring shell,那非常简单,您只需通过 WebSocketConfigurer
公开一个标准的 WebSocket,然后添加一个 WebSocketHandler
执行命令,然后将结果字符串作为 TextMessage
返回。
首先是允许客户端连接到“cli”端点的套接字配置
@Configuration
@EnableWebSocket
public class WebSocketConfiguration implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(cliHandler(), "/cli").setAllowedOrigins("*");
}
@Bean
public CLIWebSocketHandler cliHandler() {
return new CLIWebSocketHandler();
}
}
然后是执行命令的WebSocketHandler。我建议您将返回类型指定为 String
的每个 @ShellMethod
,不要使用日志记录或系统写入,因为它们不会在评估期间返回。
@Component
public class CLIWebSocketHandler extends TextWebSocketHandler {
@Autowired
private Shell shell;
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
String result = shell.evaluate(() -> message.getPayload()).toString();
session.sendMessage(new TextMessage(result));
}
}
您可以使用像 Simple WebSocket Client 这样的扩展名要对其进行测试,请转至 ws://localhost:port/cli
这是最基本的解决方案,在此之后添加安全性等功能应该很容易。请注意,我没有使用 STOMP,因为您可能想要隔离用户。但它可以与基于 STOMP 的端点一起工作,因此您可以为项目的其他部分提供发布-订阅功能。
从这个问题来看,我觉得您想要的答案涉及输入和输出流。您可能会考虑将 Spring Shell 的输出重定向到不同的流,然后将它们转发到 session ,但它可能要复杂得多并且有其他权衡。只返回一个字符串作为结果更简单,无论如何它在打印输出中看起来更好。
关于java - 有没有办法获得从客户端浏览器到模拟 shell 的服务器应用程序的双向连接?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57135669/
我相信我在子 shell 中调用 exit 会导致我的程序继续: #!/bin/bash grep str file | while read line do exit 0 done
我相信我在子 shell 中调用 exit 会导致我的程序继续: #!/bin/bash grep str file | while read line do exit 0 done
我有几个脚本,它们的第一部分看起来是一样的。这部分的功能是识别脚本在哪台机器上运行并相应地设置几个变量。它看起来像这样: ENV=`echo $LOGNAME | cut -c1-8` if
这是我正在尝试做的事情。我有 4 个 shell 脚本。脚本 1 需要先运行,然后是 2,然后是 3,然后是 4,并且它们必须按此顺序运行。脚本 1 需要运行(并在后台等待)2 才能正常运行,但是脚本
我有一个名为 a.sh 的脚本,其中的内容是: //a.sh: #!/bin/bash temp=0 while [ "$temp" -ne 500 ] do echo `date`
在snakemake中,使用shell()函数执行多个命令的推荐方式是什么? 最佳答案 您可以调用shell()多次内run规则块(规则可以指定 run: 而不是 shell: ): rule pro
我有一个 shell 脚本,我向其中传递了一些参数。Test1.sh -a 1 -b 2 -c“一二三” 在 Test1.sh 中,我按以下方式调用另一个 shell 脚本。Test2.sh $* 我
我有 2 个 shell 脚本。 第二个shell脚本包含以下函数第二个.sh func1 func2 first.sh 将使用一些参数调用第二个 shell 脚本, 将使用特定于该函数的一些其他参数
我有一个 Unix shell 脚本 test.sh。在脚本中,我想调用另一个 shell,然后从子 shell 执行 shell 脚本中的其余命令并退出 说清楚: test.sh #! /bin/b
我想在 shell 脚本中更改路径环境变量。路径变量需要在shell脚本执行后修改。 最佳答案 我知道有两种方法可以做到这一点。第一种是在当前 shell 的上下文中运行脚本: . myscript.
此 shell 脚本按预期运行。 trap 'echo exit' EXIT foo() { exit } echo begin foo echo end 这是输出。 $ sh foo.sh
我正在使用 vimshell在 vim 中执行命令 nnoremap vs :VimShellPop 使用此键映射,我可以打开 vim shell 并执行诸如“捆绑安装”之类的命令,然后 输入 exi
我想连接到不同的 shell(csh、ksh 等)并在每个切换的 shell 中执行命令。 下面是反射(reflect)我的意图的示例程序: #!/bin/bash echo $SHELL csh e
我目前正在尝试使用 BNF 和 LL 解析器在 C 中重新编写 shell。 否则,我需要知道 shell 运算符的优先级是什么| , > , > , & , ; ? 有没有人可以提供给我? 谢谢 最
不幸的是,我没有suspend 命令(busybox/ash)。但是我可以使用 kill -STOP $$ 从后台 shell (sh &) 返回到父 shell(以及 fg 之后)。 但是我不想输入
我需要知道,当用户切换到另一个 shell 时,通过单击它。 我试过 shellListener.shellDeactivated()但是当 shell 失去对它自己的控件的焦点时,会触发此事件,这意
file1.txt aaaa bbbb cccc dddd eeee file2.txt DDDD cccc aaaa 结果 bbbb eeee 如果能不区分大小写就更好了! 谢谢! 最佳答案 gre
我见过解压缩目录中所有 zip 文件的循环。但是,在运行此之前,我宁愿确保我将要运行的内容正常工作: for i in dir; do cd $i; unzip '*.zip'; rm -rf *.z
我对编程还很陌生,但我想知道 vim、emacs、nano 等 shell 文本编辑器如何能够控制命令行窗口。我主要是一名 Windows 程序员,所以可能在 *nix 上有所不同。据我所知,只能将文
我有一个包含第 7 列日期的文件,我的要求是将它与今天的日期进行比较,如果小于它,则删除该完整行。 此外,如果第 7 列中提到的任何日期超过 15 天,则将其修改为最多 15 天 下面的例子- now
我是一名优秀的程序员,十分优秀!