Spring Boot嵌入式HornetQ集群未转发消息。

104
我正在尝试创建一个由两个Spring Boot应用程序组成的静态集群,应用程序中包含嵌入式HornetQ服务器。一个应用程序/服务器将处理外部事件并生成要发送到消息队列的消息。另一个应用程序/服务器将侦听消息队列并处理传入的消息。由于两个应用程序之间的链接不可靠,因此每个应用程序将仅使用本地/ inVM客户端在其各自的服务器上生成/消费消息,并依赖于集群功能将消息转发到集群中其他服务器上的队列。
我正在使用“HornetQConfigurationCustomizer”来自定义嵌入式HornetQ服务器,因为默认情况下它只带有“InVMConnectorFactory”。
我已经创建了一些示例应用程序,说明了这种设置,在这个示例中,“ServerSend”表示将生成消息的服务器,“ServerReceive”表示将消费消息的服务器。
两个应用程序的pom.xml都包含:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-hornetq</artifactId>
</dependency>
<dependency>
    <groupId>org.hornetq</groupId>
    <artifactId>hornetq-jms-server</artifactId>
</dependency>

DemoHornetqServerSendApplication:

@SpringBootApplication
@EnableScheduling
public class DemoHornetqServerSendApplication {
    @Autowired
    private JmsTemplate jmsTemplate;
    private @Value("${spring.hornetq.embedded.queues}") String testQueue;

    public static void main(String[] args) {
        SpringApplication.run(DemoHornetqServerSendApplication.class, args);
    }

    @Scheduled(fixedRate = 5000)
    private void sendMessage() {
        String message = "Timestamp from Server: " + System.currentTimeMillis();
        System.out.println("Sending message: " + message);
        jmsTemplate.convertAndSend(testQueue, message);
    }

    @Bean
    public HornetQConfigurationCustomizer hornetCustomizer() {
        return new HornetQConfigurationCustomizer() {

            @Override
            public void customize(Configuration configuration) {
                String serverSendConnectorName = "server-send-connector";
                String serverReceiveConnectorName = "server-receive-connector";

                Map<String, TransportConfiguration> connectorConf = configuration.getConnectorConfigurations();

                Map<String, Object> params = new HashMap<String, Object>();
                params.put(TransportConstants.HOST_PROP_NAME, "localhost");
                params.put(TransportConstants.PORT_PROP_NAME, "5445");
                TransportConfiguration tc = new TransportConfiguration(NettyConnectorFactory.class.getName(), params);
                connectorConf.put(serverSendConnectorName, tc);

                Set<TransportConfiguration> acceptors = configuration.getAcceptorConfigurations();
                tc = new TransportConfiguration(NettyAcceptorFactory.class.getName(), params);
                acceptors.add(tc);

                params = new HashMap<String, Object>();
                params.put(TransportConstants.HOST_PROP_NAME, "localhost");
                params.put(TransportConstants.PORT_PROP_NAME, "5446");
                tc = new TransportConfiguration(NettyConnectorFactory.class.getName(), params);
                connectorConf.put(serverReceiveConnectorName, tc);

                List<String> staticConnectors = new ArrayList<String>();
                staticConnectors.add(serverReceiveConnectorName);
                ClusterConnectionConfiguration conf = new ClusterConnectionConfiguration(
                        "my-cluster", // name
                        "jms", // address
                        serverSendConnectorName, // connector name
                        500, // retry interval
                        true, // duplicate detection
                        true, // forward when no consumers
                        1, // max hops
                        1000000, // confirmation window size
                        staticConnectors, 
                        true // allow direct connections only
                        );
                configuration.getClusterConfigurations().add(conf);

                AddressSettings setting = new AddressSettings();
                setting.setRedistributionDelay(0);
                configuration.getAddressesSettings().put("#", setting);
            }
        };
    }
}

应用程序属性文件(ServerSend):

spring.hornetq.mode=embedded
spring.hornetq.embedded.enabled=true
spring.hornetq.embedded.queues=jms.testqueue
spring.hornetq.embedded.cluster-password=password

DemoHornetqServerReceiveApplication:

@SpringBootApplication
@EnableJms
public class DemoHornetqServerReceiveApplication {
    @Autowired
    private JmsTemplate jmsTemplate;
    private @Value("${spring.hornetq.embedded.queues}") String testQueue;

    public static void main(String[] args) {
        SpringApplication.run(DemoHornetqServerReceiveApplication.class, args);
    }

    @JmsListener(destination="${spring.hornetq.embedded.queues}")
    public void receiveMessage(String message) {
        System.out.println("Received message: " + message);
    }

    @Bean
    public HornetQConfigurationCustomizer hornetCustomizer() {
        return new HornetQConfigurationCustomizer() {

            @Override
            public void customize(Configuration configuration) {
                String serverSendConnectorName = "server-send-connector";
                String serverReceiveConnectorName = "server-receive-connector";

                Map<String, TransportConfiguration> connectorConf = configuration.getConnectorConfigurations();

                Map<String, Object> params = new HashMap<String, Object>();
                params.put(TransportConstants.HOST_PROP_NAME, "localhost");
                params.put(TransportConstants.PORT_PROP_NAME, "5446");
                TransportConfiguration tc = new TransportConfiguration(NettyConnectorFactory.class.getName(), params);
                connectorConf.put(serverReceiveConnectorName, tc);

                Set<TransportConfiguration> acceptors = configuration.getAcceptorConfigurations();
                tc = new TransportConfiguration(NettyAcceptorFactory.class.getName(), params);
                acceptors.add(tc);

                params = new HashMap<String, Object>();
                params.put(TransportConstants.HOST_PROP_NAME, "localhost");
                params.put(TransportConstants.PORT_PROP_NAME, "5445");
                tc = new TransportConfiguration(NettyConnectorFactory.class.getName(), params);
                connectorConf.put(serverSendConnectorName, tc);

                List<String> staticConnectors = new ArrayList<String>();
                staticConnectors.add(serverSendConnectorName);
                ClusterConnectionConfiguration conf = new ClusterConnectionConfiguration(
                        "my-cluster", // name
                        "jms", // address
                        serverReceiveConnectorName, // connector name
                        500, // retry interval
                        true, // duplicate detection
                        true, // forward when no consumers
                        1, // max hops
                        1000000, // confirmation window size
                        staticConnectors, 
                        true // allow direct connections only
                        );
                configuration.getClusterConfigurations().add(conf);

                AddressSettings setting = new AddressSettings();
                setting.setRedistributionDelay(0);
                configuration.getAddressesSettings().put("#", setting);
            }
        };
    }
}

应用程序属性(ServerReceive):

spring.hornetq.mode=embedded
spring.hornetq.embedded.enabled=true
spring.hornetq.embedded.queues=jms.testqueue
spring.hornetq.embedded.cluster-password=password

启动两个应用程序后,日志输出显示如下内容:

ServerSend:

2015-04-09 11:11:58.471  INFO 7536 --- [           main] org.hornetq.core.server                  : HQ221000: live server is starting with configuration HornetQ Configuration (clustered=true,backup=false,sharedStore=true,journalDirectory=C:\Users\****\AppData\Local\Temp\hornetq-data/journal,bindingsDirectory=data/bindings,largeMessagesDirectory=data/largemessages,pagingDirectory=data/paging)  
2015-04-09 11:11:58.501  INFO 7536 --- [           main] org.hornetq.core.server                  : HQ221045: libaio is not available, switching the configuration into NIO  
2015-04-09 11:11:58.595  INFO 7536 --- [           main] org.hornetq.core.server                  : HQ221043: Adding protocol support CORE  
2015-04-09 11:11:58.720  INFO 7536 --- [           main] org.hornetq.core.server                  : HQ221003: trying to deploy queue jms.queue.jms.testqueue  
2015-04-09 11:11:59.568  INFO 7536 --- [           main] org.hornetq.core.server                  : HQ221020: Started Netty Acceptor version 4.0.13.Final localhost:5445  
2015-04-09 11:11:59.593  INFO 7536 --- [           main] org.hornetq.core.server                  : HQ221007: Server is now live  
2015-04-09 11:11:59.593  INFO 7536 --- [           main] org.hornetq.core.server                  : HQ221001: HornetQ Server version 2.4.5.FINAL (Wild Hornet, 124)   [c139929d-d90f-11e4-ba2e-e58abf5d6944] 

服务器接收:

2015-04-09 11:12:04.401  INFO 4528 --- [           main] org.hornetq.core.server                  : HQ221000: live server is starting with configuration HornetQ Configuration (clustered=true,backup=false,sharedStore=true,journalDirectory=C:\Users\****\AppData\Local\Temp\hornetq-data/journal,bindingsDirectory=data/bindings,largeMessagesDirectory=data/largemessages,pagingDirectory=data/paging)  
2015-04-09 11:12:04.410  INFO 4528 --- [           main] org.hornetq.core.server                  : HQ221045: libaio is not available, switching the configuration into NIO  
2015-04-09 11:12:04.520  INFO 4528 --- [           main] org.hornetq.core.server                  : HQ221043: Adding protocol support CORE  
2015-04-09 11:12:04.629  INFO 4528 --- [           main] org.hornetq.core.server                  : HQ221003: trying to deploy queue jms.queue.jms.testqueue  
2015-04-09 11:12:05.545  INFO 4528 --- [           main] org.hornetq.core.server                  : HQ221020: Started Netty Acceptor version 4.0.13.Final localhost:5446  
2015-04-09 11:12:05.578  INFO 4528 --- [           main] org.hornetq.core.server                  : HQ221007: Server is now live  
2015-04-09 11:12:05.578  INFO 4528 --- [           main] org.hornetq.core.server                  : HQ221001: HornetQ Server version 2.4.5.FINAL (Wild Hornet, 124)   [c139929d-d90f-11e4-ba2e-e58abf5d6944] 

我在两个输出中看到了 clustered=true,如果我从 HornetQConfigurationCustomizer 中移除了集群配置,它将显示为 false,因此它必须具有某种作用。

现在,ServerSend 在控制台输出中显示了这个:

Sending message: Timestamp from Server: 1428574324910  
Sending message: Timestamp from Server: 1428574329899  
Sending message: Timestamp from Server: 1428574334904  

然而,ServerReceive 没有显示任何内容。

从 ServerSend 到 ServerReceive 没有转发消息。

我进行了更多的测试,创建了两个进一步的 Spring Boot 应用程序(ClientSend 和 ClientReceive),它们 没有 嵌入 HornetQ 服务器,而是连接到一个“本地”服务器。

这两个客户端应用程序的 pom.xml 都包含以下内容:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-hornetq</artifactId>
</dependency>

DemoHornetqClientSendApplication:

@SpringBootApplication
@EnableScheduling
public class DemoHornetqClientSendApplication {
    @Autowired
    private JmsTemplate jmsTemplate;
    private @Value("${queue}") String testQueue;

    public static void main(String[] args) {
        SpringApplication.run(DemoHornetqClientSendApplication.class, args);
    }

    @Scheduled(fixedRate = 5000)
    private void sendMessage() {
        String message = "Timestamp from Client: " + System.currentTimeMillis();
        System.out.println("Sending message: " + message);
        jmsTemplate.convertAndSend(testQueue, message);
    }
}

应用程序属性 (ClientSend):

spring.hornetq.mode=native
spring.hornetq.host=localhost
spring.hornetq.port=5446

queue=jms.testqueue

DemoHornetqClientReceiveApplication:

@SpringBootApplication
@EnableJms
public class DemoHornetqClientReceiveApplication {
    @Autowired
    private JmsTemplate jmsTemplate;
    private @Value("${queue}") String testQueue;

    public static void main(String[] args) {
        SpringApplication.run(DemoHornetqClientReceiveApplication.class, args);
    }

    @JmsListener(destination="${queue}")
    public void receiveMessage(String message) {
        System.out.println("Received message: " + message);
    }
}

应用程序属性文件(ClientReceive):

spring.hornetq.mode=native
spring.hornetq.host=localhost
spring.hornetq.port=5445

queue=jms.testqueue

现在控制台显示如下内容:

ServerReceive:

Received message: Timestamp from Client: 1428574966630  
Received message: Timestamp from Client: 1428574971600  
Received message: Timestamp from Client: 1428574976595  

客户端接收:

Received message: Timestamp from Server: 1428574969436  
Received message: Timestamp from Server: 1428574974438  
Received message: Timestamp from Server: 1428574979446  

如果我运行了 ServerSend 一段时间,然后启动 ClientReceive,它也会接收到到目前为止排队的所有消息,这表明消息并不是消失在某个地方或从别处被消耗掉。

为了完整起见,我还将 ClientSend 指向 ServerSendClientReceive 指向 ServerReceive ,以查看聚集和 InVM 客户端是否存在问题,但是没有任何输出表明任何消息已在 ClientReceiveServerReceive 中接收到。

因此,似乎嵌入式代理与直接连接的外部客户端之间的消息传递正常,但是代理之间没有转发任何消息。所以,经过这一切,重要的问题是,设置有什么问题导致消息不能在群集中转发?


你在过去的一个月里找到这个问题的答案了吗?我在互联网上什么都没找到(除了这篇帖子),关于Spring Boot和HornetQ之间两个进程的通信... - Cristina_eGold
@deepdownunder2222 到目前为止没有什么运气,我已经成功地将两个外部经纪人聚类,但即使如此,它也没有像我预期的那样100%工作,所以我暂时搁置了这个问题。我已经用ActiveMq做到了我需要的事情,但它也还没有过原型阶段。根据我在问题中描述的,似乎这不是一个受欢迎的事情,还没有引起太多兴趣。 - ci_
2
你有没有考虑设置一个桥接器呢?从架构角度来看,它似乎更符合你想要实现的目标:http://docs.jboss.org/hornetq/2.2.5.Final/user-manual/en/html/core-bridges.html - grahamrb
我同意grahamrb的观点,我曾经为这种情况使用过桥接器,我们有4台服务器,其中2台应该是唯一能够接收特定类型消息的服务器。桥接器在这种情况下效果更好。 - pczeus
forward-when-no-consumers=true会有问题。你应该将其设置为false。你不希望消息转发到集群中没有可用消费者处理消息的节点,这就是消息被“卡住”的原因。另外,由于你正在进行集群化,要记住源服务器ServerSend也是集群的一部分。因此,HornetQ可以并且会优化并在localVM内保留消息。即使它没有这样做,ServerSend也在集群中并将共享负载/消息。forward-when-no-consumers=false在这里有帮助。 - pczeus
3个回答

1

http://docs.jboss.org/hornetq/2.2.5.Final/user-manual/en/html/architecture.html#d0e595

"HornetQ核心被设计为一组简单的POJO,因此如果您的应用程序需要内部的消息传递功能,但您不想将其公开为HornetQ服务器,则可以直接实例化和嵌入HornetQ服务器到您自己的应用程序中。"
"如果您将其嵌入,则不会将其公开为服务器。每个容器都有一个单独的实例。这相当于启动2个副本并给它们相同的队列名称。其中一个在第一个实例上写入该队列,而另一个在第二个实例上监听该队列。"
"如果您想以这种方式解耦您的应用程序,则需要一个充当服务器的单一位置。可能,您想要进行集群。顺便说一下,这不是Hornet特有的。您经常会发现这种模式。"

1
我对这个答案并不满意。1. 引用的文档并没有明确说明我正在尝试做的事情是不可能完成的。2. 我已经将嵌入式服务器暴露给外部访问,即从外部客户端连接它,这方面没有问题。3. 是的,集群正是我正在寻找的,也正是这个问题所涉及的,而且也正是 起作用的地方。 - ci_
1
ci_ 实际上,聚类并不是您要寻找的东西。聚类用于允许冗余和分配以及共享负载。您正在尝试使用一个服务器直接发送到另一个服务器。可以完成吗?是的。聚类的目的是什么?不是这个。 - pczeus

0

筛选器

package it.unitn.disi.webdev.claudiovigliarolo;

import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

@WebFilter(filterName = "AuthenticationFilter", urlPatterns = { "/*" })
public class AuthenticationFilter implements Filter {
    private ServletContext context;

    public void init(FilterConfig fConfig) throws ServletException {
        this.context = fConfig.getServletContext();
        this.context.log("AuthenticationFilter initialized");
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)

            throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;
        String uri = req.getRequestURI();
        HttpSession session = req.getSession(false);
        boolean isLoggedIn = session != null && session.getAttribute("username") != null;

        if (!isLoggedIn && !uri.endsWith("start.jsp")) {
            res.sendRedirect("start.jsp");

        } else {
            chain.doFilter(request, response);
        }
    }

    public void destroy() {
        // close any resources here
    }
}<filter-mapping><filter-name>AuthenticationFilter</filter-name><url-pattern>/*</url-pattern>
  </filter-mapping>




import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

@WebServlet(name = "GetItems", urlPatterns = { "/GetItems" })
public class GetItems extends HttpServlet {

    String dbURL = "jdbc:derby://localhost:1527/ExamDerbyDB";
    String user = "WEBENGINE";
    String password = "WEBENGINE";
    Connection conn = null;

    @Override
    public void init() {
        try {
            Class.forName("org.apache.derby.jdbc.ClientDriver");
            conn = DriverManager.getConnection(dbURL, user, password);
        } catch (ClassNotFoundException | SQLException ex) {
            ex.printStackTrace();

        }
    }

    @Override
    public void destroy() {
        try {
            if (conn != null) {
                conn.close();
            }
        } catch (SQLException ex) {
            System.err.println("Database connection problem: can't close connection");

        }
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/html;charset=UTF-8");
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        StringBuilder ret = new StringBuilder();

        ArrayList<String> inserted = getAllItemsFromDB();

        String jsonResponse = getListJson(inserted);
        response.setContentType("application/json;charset=UTF-8");
        try (PrintWriter out = response.getWriter()) {

            out.println(jsonResponse);
        }
    }

    private ArrayList<String> getAllItemsFromDB() throws ServletException {
        ArrayList elements = new ArrayList();
        
        PreparedStatement stm = null;
        ResultSet result = null;
        
        try {
            String query = "SELECT USERNAME FROM USERS";
            stm = conn.prepareStatement(query);
            result = stm.executeQuery();
            while(result.next()) {
                String string = result.getString(1); 
                elements.add(string);
            }
            stm.close();
            result.close();

        } catch (SQLException ex) {
            System.err.println("Database connection problem");
        } finally {
            try {
                if(stm != null) stm.close();
                if(result != null) result.close();
            } catch (SQLException ex) {
               System.err.println("Database connection problem: can't close statement/result");
            }
        
        return elements;
    }

    public String getListJson(ArrayList<String> list) {
        if (list.size() == 0)
            return null;
        StringBuilder ret = new StringBuilder("[");
        String prefix = "";
        for (int i = 0; i < list.size(); i++) {
            StringBuilder sb = new StringBuilder();
            ret.append(prefix);
            prefix = ",";
            ret.append(sb.append("{\"message\":\"").append(list.get(i)).append("\"}").toString());
        }
        ret.append("]");
        return ret.toString();
    }
}

class.java

public class MessageList {
    protected final LinkedList<Message> list;

    public MessageList() {
        this.list = new LinkedList<>();
    }

    public void addMessage(Message m) {
        this.list.add(m);
    }

    public void deleteMessage(String message_id) {
        for (Message a : list) {
            if (a.message_id.equals(message_id)) {
                list.remove(a);
            }
        }
    }

    public Message getMessage(String message_id) {
        for (Message a : list) {
            if (a.message_id.equals(message_id)) {
                return a;
            }
        }
        return null;

    }

    public void addLike(String message_id) {
        for (Message a : list) {
            if (a.message_id.equals(message_id)) {
                a.isLiked++;
            }
        }
    }

    StringBuilder ret = new StringBuilder("[");
    String prefix = "";for(
    int i = 0;i<list.size();i++)
    {
        Message m = list.get(i);
        ret.append(prefix);
        prefix = ",";
        ret.append(m.toJson());
    }ret.append("]");

    return ret.toString();
    }

    public String getListJson()
    {
        if(list.size() == 0)
        {
            return null;
        }
        
        StringBuilder ret = new StringBuilder("[");
        String prefix = "";
        for(int i=0; i<list.size(); i++) {
            StringBuilder sb = new StringBuilder();
            ret.append(prefix);
            prefix = ",";
            ret.append(sb.append("{\"message\":\"").append(list.get(i)).append("\"}").toString());
        }
        ret.append("]");
        
        return ret.toString();
    }
}

表单

<!DOCTYPE html>
<html lang="en">
  <body>
    <script>
      function validateForm(form) {
        var username = document.getElementById("username").value;
        var password = document.getElementById("password").value;
        var error = document.getElementById("error");
        error.innerHTML = "";
        if (username === "" || password == "") {
          form.reset();
          error.innerHTML = "password / username empty";
          return false;
        }
        return true;
      }
    </script>

    <div class="container" style="width: 500px; float: left">
      <h2 class="text-center">Welcome to the App</h2>
      <form
        id="registerForm"
        method="POST"
        onsubmit="return validateForm(this)"
        action="Registration"
      >
        <div class="form-group">
          <label for="username">Username:</label>
          <input
            type="text"
            class="form-control"
            id="username"
            placeholder="Enter email"
            name="username"
          />
        </div>
        <div class="form-group">
          <label for="password">Password:</label>
          <input
            type="password"
            class="form-control"
            id="password"
            placeholder="Enter password"
            name="password"
          />
        </div>
        <div class="form-group form-check"></div>
        <button type="submit" class="btn btn-primary">Submit</button>
      </form>
      <div id="error" class="alert" role="alert"></div>
    </div>
  </body>
</html>

概述

//servelet context
ServletContext application=getServletContext();
application.setAttribute("messages", messages);



//SESSION
HttpSession session = request.getSession();
String name = (String) request.getParameter("username");
session.setAttribute("username", name);


//random id java
String uniqueID = UUID.randomUUID().toString();

//package
it.unitn.disi.webdev.claudiovigliarolo

//project name
VIGLIAROLO_C_202314

//get contextpath
    String contextPath = request.getContextPath();
        System.out.println("Context Path = " + contextPath);
        response.sendRedirect(contextPath + "/main.html");


//BOOTstrap
  <head>
    <title>Bootstrap Example</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
  </head>



//redirect to other page
window.location.replace("http://stackoverflow.com");



//CONTENT type
response.setContentType("application/json;charset=UTF-8");  
response.setContentType("text/html;charset=UTF-8");






//zuccherino
    protected final LinkedList<Message> list;
    
      public MessageList() {
        this.list = new LinkedList<>();
    }



<!DOCTYPE html>
<html lang="en">
<body>
<script>
function validateForm(form) {
    var username = document.getElementById("username").value;
     var password = document.getElementById("password").value;
      var error = document.getElementById("error");
      error.innerHTML = "";
    if(username === "" || password == "") {
         form.reset();
         error.innerHTML = "password / username empty";
         return false;
    }
   return true;
}
</script>

<div class="container " style="width:500px; float: left;">
   
  <h2 class="text-center">Welcome to the App</h2>
  <form id="registerForm" method="POST" onsubmit="return validateForm(this)" action="Registration">
    <div class="form-group">
      <label for="username">Username:</label>
      <input type="text" class="form-control" id="username" placeholder="Enter email" name="username">
    </div>
    <div class="form-group">
      <label for="password">Password:</label>
      <input type="password" class="form-control" id="password" placeholder="Enter password" name="password">
    </div>
    <div class="form-group form-check">
    </div>
    <button type="submit" class="btn btn-primary">Submit</button>
  </form>
 <div id="error" class="alert" role="alert">
  
</div>
</div>
</body>
</html>


//change styles
 const val =  keywords.some(k=>item.message.includes(k));
const color = val ? "#FFFF00;" : "transparent;";
document.getElementById("data").innerHTML +=
        "<div style=' margin-top:50px;flexdirection: row; display:flex; width:500px; background:" + color + "; justify-content: row; '>" +
        item.message +
        "</div>";


//setimeout
function refresh() {
// make Ajax call here, inside the callback call:
setTimeout(refresh, 5000);
// ...
}
// initial call, or just call refresh directly
setTimeout(refresh, 5000);


//template strings
`string text`

获取克劳迪奥发布克劳迪奥


<script>
  function onSendData() {
    var title = document.getElementById("username").value;
    var description = document.getElementById("password").value;
    console.log(title, description);
    var http = new XMLHttpRequest();
    var url = "Registration";
    var params = "password=" + description + "&username=" + title;
    http.open("POST", url, true);
    //Send the proper header information along with the request
    http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    http.onreadystatechange = function () {
      //Call a function when the state changes.
      if (http.readyState == 4 && http.status == 200) {
        console.log("res", http.responseText);
      }
    };
    http.send(params);
  }
</script>
------GET---------------
  //loadData noparam
<script>

  loadData();

function loadData() {
    var xhttp = new XMLHttpRequest();
    xhttp.open("GET", "GetProducts", true);
    xhttp.responseType = "json";
    xhttp.onreadystatechange = function () {
        var done = 4,
                ok = 200;
        if (this.readyState === done && this.status === ok) {
            my_JSON_object = this.response;
            console.log("response", my_JSON_object);
            document.getElementById("data").innerHTML = "";
            my_JSON_object && my_JSON_object.forEach((item) => {
                console.log("item", item.message);
                document.getElementById("data").innerHTML +=
                        " <div class='card' style='width: 300px; margin-top:50px;'>" +
                        "<div class='card-body'>" +
                        " <h4 class='card-title'>" + item.name + "</h4>" +
                        "<p class='card-text'>" + item.description + "</p>" +
                        "  <p class='card-text'>Price: " + item.price + " $</p>" +
                        "    <a href='detail.html?name=" + item.name + "' class='card-link' >View details</a>" +
                        "   </div>    </div>";
            });
        }
    };
    xhttp.send();
}
</script>
<div id="data"></div>

 //loadData withparam
<script>
  function getData() {
  const urlParams = new URLSearchParams(window.location.search);
  const id = urlParams.get('id');
  const id2 = urlParams.get('id2');

  console.log(id)
  var url = "GetItems";
  let param1 = id;
  let param2 = id2;
  var params = "param1=" + param1 + "&param2=" + param2;
  var http = new XMLHttpRequest();
  http.open("GET", url + "?" + params, true);
  http.responseType = "json";
  http.onreadystatechange = function () {
      var done = 4,
              ok = 200;
      if (this.readyState === done && this.status === ok) {
          my_JSON_object = this.response;
          console.log("response", my_JSON_object);
          document.getElementById("data").innerHTML = "";
          my_JSON_object && my_JSON_object.forEach((item) => {
              console.log("item", item.message);
              document.getElementById("data").innerHTML +=
                      "<div style=' margin-top:50px;flexdirection: row; display:flex; width:500px; justify-content: row; '>" +
                      item.message +
                      "</div>";
          });
      }
  };
  http.send(null);
}
</script>
<div id="data"></div>







<div class="card" style="margin-top: 50px;">
  <div class="card-body">Content</div>
</div>


//render multiple parameters
onclick="showData('${item.name}', '${item.price}', '${item.punteggio}', '${item.extra}' )"

JSON servelet claudio


RETURN JSON
//create simple json response
response.setContentType("application/json;charset=UTF-8");  
StringBuilder ret = new StringBuilder();
ret.append("{\"ready\":\"").append("false").append("\"}");
try (PrintWriter out = response.getWriter()) {
    out.println(ret.toString());
}

JSON LIST CLASS
     public String toJSON() {
        StringBuilder ret = new StringBuilder("[");
        String prefix = "";
        for(int i=0; i<list.size(); i++) {
            Message m = list.get(i);
            ret.append(prefix);
            prefix = ",";
            ret.append(m.toJson());
        }
        ret.append("]");
                System.err.println("priting tojson"+ ret.toString());
        return ret.toString();
    }


JSON ITEM
    public String toJson() {
        StringBuilder ret = new StringBuilder();
        ret.append("{\"id\":\"").append(this.id).append("\",");
        ret.append("\"nome\":\"").append(this.nome).append("\",");
        ret.append("\"imgName\":\"").append(this.imgName).append("\"}");
        return ret.toString();
    }




STRING LIST
    public String wordsToJSON(ArrayList<String> list) {
        System.err.println("lunghezza" + list.size());
        if (list.size() == 0) {
            return null;
        }
        StringBuilder ret = new StringBuilder("[");
        String prefix = "";
        for (int i = 0; i < list.size(); i++) {
            StringBuilder sb = new StringBuilder();
            ret.append(prefix);
            prefix = ",";
            ret.append(sb.append("{\"message\":\"").append(list.get(i)).append("\"}").toString());
        }

        ret.append("]");
        System.err.println("jjj" + ret.toString());
        return ret.toString();
    }

    }
JSON RESPONSE OK
           ServletContext application=getServletContext();
            MappaDiCoppie mappaDiCoppie =  (MappaDiCoppie) application.getAttribute("mappaDiCoppie");
            HttpSession session= request.getSession();
            String username = (String) session.getAttribute("username");
            StringBuilder ret = new StringBuilder();
            if(mappaDiCoppie != null && username != null)
            {
                if(mappaDiCoppie.exists(username))
                    //ok 
                    ret.append("{\"ready\":\"").append("true").append("\"}");
                else  
                    //no wait
                    ret.append("{\"ready\":\"").append("false").append("\"}")
                    try (PrintWriter out = response.getWriter()) {
                    out.println(ret.toString());
                }
            }


            ```

















1
嗨@roman,你能否写一些关于你的解决方案或者你如何用代码尝试解决这个问题的文字?另外,你的回答很长,你可能想要专注于主要问题。 - Janos Vinceller

0

样式表

 <link rel="stylesheet" href="./styles/styles.css">
  <script type="text/javascript" src="./js/script.js"></script>

矩阵 HTML

 const N = 9;
const container = document.getElementById("container");

function makeRows(rows, cols) {
    container.style.setProperty('--grid-rows', rows);
    container.style.setProperty('--grid-cols', cols);
    for (c = 0; c < (cols); c++) {
        for (r = 0; r < rows; r++) {
            const myid = JSON.stringify({x: r, y: c});
            let cell = document.createElement("div");
            var textnode = document.createElement("span");
            textnode.setAttribute("id", myid);
            cell.appendChild(textnode);
            cell.onclick = function (event) {
                showVal(myid, r, c);
            }
            //cell.innerText = (c + 1);
            container.appendChild(cell).className = "grid-item";
            container.appendChild(cell).style = "border-color: red";
            container.appendChild(cell).style = "border-width: 4px";

        }
        ;
    }
}

//styles

.myinput{
    width: 50px;
    margin-right: 20px;
}


#container {
  display: grid;
  grid-gap: .5em;
  grid-template-rows: repeat(var(--grid-rows), 1fr);
  grid-template-columns: repeat(var(--grid-cols), 1fr);
  width: 100px;
}

.grid-item {
  border: 1px solid #ddd;
  text-align: center;
  width: 50px;
  height: 50px;
  border-width: 2px;
  border-color: green;
  
}

网格Java

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package utils;

import java.util.ArrayList;
import java.util.Random;

/**
 *
 * @author claud
 */
public class Grid {

int N;
Cell[][] matrix;

public Grid(int N) {
    this.N = N;
    this.matrix = new Cell[N][N];
}

private int getRandom() {
    Random rn = new Random();
    int range = 0 - 0 + 1;
    int randomNum = rn.nextInt(N) + 0;
    return randomNum;
}

public int getValue(int x, int y) {
    if (x < N && y < N) {
        return this.matrix[x][y].value;
    } else {
        return -2;
    }
}

public void generate() {
    System.err.println("ffffffffffffggg");

    //fai il ciclo completo
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            this.matrix[i][j] = new Cell(i, j, 0);//aggiungi bombe con random altrimenti valore 0
        }
    }
}


public void print() {
    System.err.println("printiiiiiiiiiiiing START");
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            System.err.println(this.matrix[i][j].value);
        }
    }
}
}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接