how to build console command in spring boot web application using spring shell?

无人久伴 提交于 2019-12-03 16:36:41

问题


I have created restfull web application using spring boot web starter which works well. I am able to access it through urls.

But I have requirement to create console command which can compute and store some values at the backend. I want to be able to run console command manually or through bash script.

I could not find any documentation on how to integrate spring-shell project in spring boot web application.

Also there is no option to choose spring-shell dependency in spring boot starter https://start.spring.io/

1) Do webapp and console need to be two separate applications and I need to deploy them separately ?

2) Is it possible to deploy web app and run console commands in the same app ?

3) What is the best approach to share common code (model, services, entities, business logic) between shell and web applications ?

Can anyone please help on this ?


回答1:


Here's 2 options:

(1) Rest API called from the command line

You could create a Spring @RestController, which you then call from the command line ?

curl -X POST -i -H "Content-type: application/json" -c cookies.txt -X POST http://hostname:8080/service -d '
    {
        "field":"value",
        "field2":"value2"
    }
    '

You can easily embed this in a nice shell script.

(2) Use spring-boot-remote-shell (deprecated)

Though it is mainly for monitoring/administration purposes, you may use the spring-boot-remote-shell for that.

Dependencies

You need the following dependencies to enable the remote-shell:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-remote-shell</artifactId>
</dependency>
<dependency>
    <groupId>org.crsh</groupId>
    <artifactId>crsh.shell.telnet</artifactId>
    <version>1.3.0-beta2</version>
</dependency>

Groovy script:

Add the following script in src/main/resources/custom.groovy:

package commands

import org.crsh.cli.Command
import org.crsh.cli.Usage
import org.crsh.command.InvocationContext

class custom {

    @Usage("Custom command")
    @Command
    def main(InvocationContext context) {
        return "Hello"
    }
}

To get a hold of a Spring bean from this groovy script (source: https://stackoverflow.com/a/24300534/641627):

BeanFactory beanFactory = (BeanFactory) context.getAttributes().get("spring.beanfactory");
MyController myController = beanFactory.getBean(MyController.class);

Launch your SpringBootApp

With spring-boot-remote-shell on the classpath, the Spring Boot Application listens on port 5000 (by default). You can now do this:

$ telnet localhost 5000
Trying ::1...
Connected to localhost.
Escape character is '^]'.
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::  (v1.3.5.RELEASE)

Help

You can type help to see the list of available commands:

NAME       DESCRIPTION                                                                                                                                                                 
autoconfig Display auto configuration report from ApplicationContext                                                                                                                   
beans      Display beans in ApplicationContext                                                                                                                                         
cron       manages the cron plugin                                                                                                                                                     
custom     Custom command                                                                                                                                                              
dashboard                                                                                                                                                                              
egrep      search file(s) for lines that match a pattern                                                                                                                               
endpoint   Invoke actuator endpoints                                                                                                                                                   
env        display the term env                                                                                                                                                        
filter     A filter for a stream of map                                                                                                                                                
help       provides basic help                                                                                                                                                         
java       various java language commands                                                                                                                                              
jmx        Java Management Extensions                                                                                                                                                  
jul        java.util.logging commands                                                                                                                                                  
jvm        JVM informations                                                                                                                                                            
less       opposite of more                                                                                                                                                            
log        logging commands                                                                                                                                                            
mail       interact with emails                                                                                                                                                        
man        format and display the on-line manual pages                                                                                                                                 
metrics    Display metrics provided by Spring Boot                                                                                                                                     
shell      shell related command                                                                                                                                                       
sleep      sleep for some time                                                                                                                                                         
sort       Sort a map                                                                                                                                                                  
system     vm system properties commands                                                                                                                                               
thread     JVM thread commands 

Call our custom command

Our custom command is listed (the fourth from the top), you can call it:

> custom
Hello

So, essentially, your crontab would do a telnet 5000 and execute custom

(3) How to use arguments and options (to answer question in comments)

Arguments

To use arguments, you can take a look at the documentation:

class date {
  @Usage("show the current time")
  @Command
  Object main(
     @Usage("the time format")
     @Option(names=["f","format"])
     String format) {
    if (format == null)
      format = "EEE MMM d HH:mm:ss z yyyy";
    def date = new Date();
    return date.format(format);
  }
}

% date -h
% usage: date [-h | --help] [-f | --format]
% [-h | --help]   command usage
% [-f | --format] the time format

% date -f yyyyMMdd

Sub-command (or options)

Still from their documentation:

@Usage("JDBC connection")
class jdbc {

  @Usage("connect to database with a JDBC connection string")
  @Command
  public String connect(
          @Usage("The username")
          @Option(names=["u","username"])
          String user,
          @Usage("The password")
          @Option(names=["p","password"])
          String password,
          @Usage("The extra properties")
          @Option(names=["properties"])
          Properties properties,
          @Usage("The connection string")
          @Argument
          String connectionString) {
     ...
  }

  @Usage("close the current connection")
  @Command
  public String close() {
     ...
  }
}

% jdbc connect jdbc:derby:memory:EmbeddedDB;create=true

The last command executes:

  • the command jdbc
  • with subcommand connect
  • and the argument jdbc:derby:memory:EmbeddedDB;create=true

A Complete example

The following contains:

  • a constructor;
  • a command with arguments;
  • a spring managed bean;
  • a subcommand with arguments.

The code:

package commands

import org.crsh.cli.Command
import org.crsh.cli.Usage
import org.crsh.command.InvocationContext
import org.springframework.beans.factory.BeanFactory
import com.alexbt.goodies.MyBean

class SayMessage {
    String message;
    SayMessage(){
        this.message = "Hello";
    }

    @Usage("Default command")
    @Command
    def main(InvocationContext context, @Usage("A Parameter") @Option(names=["p","param"]) String param) {
        BeanFactory beanFactory = (BeanFactory) context.getAttributes().get("spring.beanfactory");
        MyBean bean = beanFactory.getBean(MyBean.class);
        return message + " " + bean.getValue() + " " + param;
    }

    @Usage("Hi subcommand")
    @Command
    def hi(InvocationContext context, @Usage("A Parameter") @Option(names=["p","param"]) String param) {
        BeanFactory beanFactory = (BeanFactory) context.getAttributes().get("spring.beanfactory");
        MyBean bean = beanFactory.getBean(MyBean.class);
        return "Hi " + bean.getValue() + " " + param;
    }
}

> saymsg -p Johnny
> Hello my friend Johnny

> saymsg hi -p Johnny
> Hi my friend Johnny



回答2:


It sounds like you have two distinct use cases here: running scheduled tasks, and running commands manually. From my understanding, Spring Shell isn't part of the Boot ecosystem. You can write a Spring Shell application that is external to your Boot Web app, but it's not going to embed within it. At least from my experience.

For the first case of scheduled tasks, you should look at Spring's Scheduler. You should be able to configure a Spring application (Boot or normal) that has a Task Scheduler within it. Then you can configure your Tasks that can be scheduled, letting the scheduler do the work.

For manually executing the commands, you do have a few options here. If you use Spring Shell, assume it's running in its own process, external to the Spring Boot process. You would need to have the Shell app call into the Boot application (presuming that's where you want to work to occur) using remote method invocation technologies (eg, RMI, REST, etc).

An alternative to Spring Shell is to embed a remote shell into your Boot application. Essentially, you can use SSH to connect to your Boot application and define commands in a similar fashion as Spring Shell. The benefit is that this is in the same process as the Boot application. So you can inject the Task Scheduler and run the same Tasks manually as are scheduled. This might be a good option if you want to manually kick of the same Tasks are being scheduled. Doco for the remote console is here.

Hope this helps



来源:https://stackoverflow.com/questions/39329017/how-to-build-console-command-in-spring-boot-web-application-using-spring-shell

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!