Can anyone teach me or direct to a working example to satisfy this requirement.
Scenario:
List item My Web App is using spring mvc.
One of the services it provides is that when the user clicks on a button a long running process will occur on the server. (Query database, write files, write logs, etc...) this process can take a few seconds or a few minutes.
*Problem***
How can I implement the service to update the client of its progress.
The service returns true or false if the process was successful.
Thanks for your replies. A code snippet or a complete tutorial will be most helpful.
Here is a possible solution to this progress bar problem:
task.jsp
<%#page contentType="text/html" pageEncoding="UTF-8"%>
<%#taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
<script src="../js/jquery.min.js"></script>
<script>
$(document).ready(function () {
$.getJSON(window.location.href.concat('/status'), function(data) {
if (data === "created") {
} else {
// task is already being executed
refreshProgress();
}
});
});
var width = 0;
function getProgress() {
$.getJSON(window.location.href.concat('/progress'), function(percentage) {
$('#progressBar').css('width', percentage+'%');
document.getElementById("label").innerHTML = percentage * 1 + '%';
width = percentage;
});
}
function start() {
$.ajax({
type: "post",
data: $('#task').serialize(),
success: function(data) {
$('#progressBar').css('width', 100+'%');
document.getElementById("label").innerHTML = 100 * 1 + '%';
// do sth with the data after finished task
}
});
width = 0;
$('#progressBar').css('width', 0+'%');
document.getElementById("label").innerHTML = 0 * 1 + '%';
refreshProgress();
}
function refreshProgress() {
$("#btnStart").prop("disabled",true);
var id = setInterval(frame, 1000);
function frame() {
if (width >= 100) {
clearInterval(id);
$("#btnStart").prop("disabled",false);
} else {
getProgress();
}
}
}
</script>
</head>
<body>
<div class="container">
<h2 class="text-center">Progress Bar Example</h2>
<div class="progress">
<div id="progressBar" class="progress-bar" role="progressbar" aria-valuenow="70" aria-valuemin="0" aria-valuemax="100" style="width:0%">
<div id="label">0%</div>
</div>
</div>
<form:form method="POST" commandName="task" cssClass="form-horizontal">
<fieldset>
<div class="form-group">
<label class="col-md-4 control-label" for="btnStart">Actions</label>
<div class="col-md-8">
<button id="btnStart" name="btnStart" class="btn btn-success">Start</button>
<button id="btnStop" name="btnStop" class="btn btn-danger">Stop</button>
</div>
</div>
</fieldset>
</form:form>
</div>
<script>
$('#task').submit(function () {
start();
return false;
});
</script>
</body>
</html>
TaskController.java
#Controller
#RequestMapping(value = "/task")
public class TaskController {
private Task task;
#RequestMapping("")
protected ModelAndView page() {
ModelAndView model = new ModelAndView(VIEW_DIR + "task");
if (this.task == null) {
this.task = new Task();
}
model.addObject("task", this.task);
return model;
}
#RequestMapping(value = "/status", method = GET)
public #ResponseBody
String getStatus() {
return task.getStatus();
}
#RequestMapping(value = "/progress", method = GET)
public #ResponseBody
int getProgress() {
return task.getProgress();
}
public ModelAndView form(#ModelAttribute Task task) {
this.task = task;
ModelAndView model = new ModelAndView(VIEW_DIR + "task");
task.execute();
model.addObject("task", this.task);
return model;
}
}
Task.java
public class Task {
private int total;
private int progress;
private String status;
public Task() {
this.status = "created";
// TODO get total here or pass via form
}
public void execute() {
status = "executing";
int i = 0;
while (i < total && status.equals("executing")) {
progress = (100 * (i + 1) / total);
i++;
}
}
public int getTotal() {
return total;
}
public void setTotal(int total) {
this.total = total;
}
public int getProgress() {
return progress;
}
public void setProgress(int progress) {
this.progress = progress;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
There are a good number of ways to handle a scenario like this. One way is to model the work in terms of a "Process", which contains a "status", including a percentage completion.
If you imagine what this might look like on a website, clicking the button to start the process would submit a form that begins the process and assigns some sort of identity to the process, almost like if you were creating any other sort of object. It would then redirect you to a "process status" page.
The process status page would query for the status of the process and display it. It'd probably have a URL parameter for the process's ID. It would perhaps update itself using an AJAX call to return a progress percentage.
On the backend, you now need to solve a couple of problems: finding out the current status of process N, and updating the status of process N. You could accomplish this in a number of ways, including storing the progress in the database or having some sort of in-memory table of running jobs. You could also use some sort of heuristic to estimate a percent. For example, if it's a "register new user" job, maybe it's 20% done if the user's table has an email address, 40% done if the user avatar table has data in it for this user, etc. I don't recommend this as much.
Related
I'm working with socketio and netty with java and I'm new to both of them.
my client side code looks like this.
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<title >webSocket test</title>
<script src="http://code.jquery.com/jquery-1.12.4.min.js"></script>
<script src="https://cdn.socket.io/3.1.3/socket.io.min.js" integrity="sha384-cPwlPLvBTa3sKAgddT6krw0cJat7egBga3DJepJyrLl4Q9/5WLra3rrnMcyTyOnh" crossorigin="anonymous"></script>
< !-- New Bootstrap core CSS file-->
<!-- Optional Bootstrap theme file (generally not necessary to import) -->
<!- -jQuery file. Be sure to introduce before bootstrap.min.js -->
<!-- The latest Bootstrap core JavaScript file-->
<script type=" text/javascript">
$(function(){
/**
* The socket.emit("event name", "parameter data") method of the
front-end js is used when triggering the back-end custom message event, * front-end js The socket.on("event name", anonymous function (data sent by the server to the client)) for monitoring server-side events
**/
//io({path: 'ws://localhost:9099/', transports: ['websocket'] ,upgrade: false});
var socket = io.connect("ws://localhost:9099",{transports: ['websocket'] ,upgrade: false});
var firstconnect = true;
if(firstconnect) {
console.log("First connection initialization");
//Monitor server connection event
socket.on('connect',function(){
socket.emit('messageEvent', 'Hello server');
console.log("First connection success");
$("#tou").html("Connect to the server successfully!");
});
//Monitor server shutdown service event
socket.on('disconnect', function(){
$("#tou").html("Disconnected from the server!");
});
//Monitor server Send message event
socket.on('responseEvent', function(data) {
console.log('data');
$("#msg").html($("#msg").html() + "<br/>" + data);
} );
firstconnect = false;
} else {
console.log("why?");
socket.socket.reconnect();
}
$('#send').bind('click', function() {
send();
});
function send(){
if (socket != null) {
var message = document.getElementById('message').value;
var title = "message";
var obj = {message:message,title:title};
var str = JSON.stringify(obj);
socket.emit("messageEvent",str);
console.log("message event" , str);
} else {
alert('Send');
}
}
});
</script>
</head>
<body>
<div class="page-header" id="tou">
webSocket Demo
</div>
<div class="well" id="msg">
</div>
<div class="col-lg">
<div class="input-group">
<input type="text" class="form-control" placeholder="send Message..." id="message">
<span class="input-group-btn">
<button class="btn btn-default" type="button" id="send" >send</button>
</span>
</div><!-- /input-group -->
</div><!-- /.col-lg-6 -->
</div><!-- /.row --><br><br>
</body>
</html>
The event handler is as shown below.
#Component
public class MessageEventHandler {
private static final Logger logger = LoggerFactory.getLogger(MessageEventHandler.class);
public static ConcurrentMap<String, SocketIOClient> socketIOClientMap = new ConcurrentHashMap<>();
#Autowired
private RedissonClient redisson;
#Resource
private SocketIOServer socketIOServer;
#OnConnect
public void onConnect(SocketIOClient client){
Map<String,Object> clientMap = new HashMap<>(16);
client.sendEvent("responseEvent", client.getSessionId().toString()+": "+ "hello");
if(client!=null){
String room = client.getHandshakeData().getSingleUrlParam("room");
String nameSpace = client.getNamespace().getName();
logger.info("namespace {} ",nameSpace);
String sessionId = client.getSessionId().toString();
logger.info("namespace, room={}, sessionId={},namespace={}",room,sessionId,nameSpace);
if(StringUtils.isEmpty(room)){
//client.joinRoom(room);
clientMap.put("rooms",room);
}
clientMap.put("createTime", LocalDateTime.now().toString());
redisson.getBucket("room"+sessionId).trySet(clientMap);
}
return;
}
/**
* Triggered when the client closes the connection
*
* #param client
*/
#OnDisconnect
public void onDisconnect(SocketIOClient client) {
logger.info("client:" + client.getSessionId() + "disconnected");
}
/**
* Client events
*
* #param client
* #param request
* #param msg
*/
#OnEvent(value = "messageEvent")
public void onMessageEvent(SocketIOClient client, AckRequest request, String msg) {
System.out.println("haha");
logger.info("message :" + msg);
//Post the message back
JSONObject jsonObject = JSON.parseObject(msg);
String message = jsonObject.getString("message");
Collection<SocketIOClient> clients = socketIOServer.getBroadcastOperations().getClients();
for (SocketIOClient clientByRoom : clients) {
clientByRoom.sendEvent("responseEvent", client.getSessionId().toString()+": "+message);
}
}
}
The server starter code is shown below.
#Component
#Order(1)
public class SocketServerRunner implements CommandLineRunner {
private static Logger logger = LoggerFactory.getLogger(SocketServerRunner.class);
#Resource
private SocketIOServer socketIOServer;
#Resource
private PubSubStore pubSubStore;
#Autowired
private RedissonClient redisson;
#Override
public void run(String... args) throws Exception {
logger.info("socketIOServer ");
socketIOServer.start();
pubSubStore.subscribe(PubSubType.DISPATCH, data -> {
Collection<SocketIOClient> clients = null;
String room = data.getRoom();
String namespace = data.getNamespace();
Packet packet = data.getPacket();
String jsonData = packet.getData();
if(!StringUtils.isEmpty(namespace)){
SocketIONamespace socketIONamespace = socketIOServer.getNamespace(namespace);
if(StringUtils.isEmpty(room)){
clients = socketIONamespace.getRoomOperations(room).getClients();
}
}else{
clients = socketIOServer.getBroadcastOperations().getClients();
}
if(!CollectionUtils.isEmpty(clients)){
for (SocketIOClient client : clients) {
client.sendEvent("messageEvent",jsonData);
}
}
}, DispatchMessage.class);
// addNameSpace(socketIOServer);
}
I'm getting a connection registration on the OnConnect annoted method, but the method seems to run two times cause I get the log twice while the socket connects. I don't know why it happens.
But even worse is the emit method doesn't work that is written in client side javascript. There is no error. The log below the emit is executed. But the OnEvent annoted method in the java EventHandler doesn't seem to detect it.
Can someone help me understand this?
Apparently it seems the problem is with the libraries. There is some compatibility issue with newer versions of socketio client library with netty dependencies for java and it is causing the weird problems.
My dependency for netty socketio is shown below which obviously is the latest as of answering this question.
<dependency>
<groupId>com.corundumstudio.socketio</groupId>
<artifactId>netty-socketio</artifactId>
<version>1.7.19</version>
</dependency>
And for the client library to work smoothly I had to downgrade the library from 3.X.X to 2.X.X .
In my case from
<script src="https://cdn.socket.io/3.1.3/socket.io.min.js" integrity="sha384-cPwlPLvBTa3sKAgddT6krw0cJat7egBga3DJepJyrLl4Q9/5WLra3rrnMcyTyOnh" crossorigin="anonymous"></script>
to
<script src="https://cdn.bootcss.com/socket.io/2.1.1/socket.io.js"></script>
I'm newbie on spring boot. I'm already implement some request mappings with successfully output in json.
localhost:8080/gJson
{
ad: "Windows 10",
mimari: "amd64",
versiyon: "10.0",
diskSize: 918,
freediskSize: 614,
cores: 8,
usablediskSize: 614
}
And My Controller here
#EnableAutoConfiguration
#Controller
public class GreetingController {
#RequestMapping(value = "/gJson", produces=MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody MyPojo gJson(){
...
}
}
And now, I need ... example when I'm going to this link > localhost:8080/GetInfo getting json from localhost:8080/gJson but every "X" seconds.
Thanks For Helping.
How is /GetInfo being served? Is it just a standard HTML page? If so you can code a Javascript element that has a setInterval() to make an XMLHttpRequest to the /gJson endpoint. There are a number of other ways to do it depending on what libraries you want to use to have browser to server communications.
* Update *
Sample project: https://github.com/ShawnTuatara/stackoverflow-38890600
Main aspect that allows the refresh is the HTML page at src/main/resources/static/GetInfo.html
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>GetInfo</title>
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
</head>
<body>
</body>
<script type="text/javascript">
$(function() {
window.setInterval(function() {
$.ajax({
url : "/gJson"
}).done(function(data, status, jqXHR) {
$("body").text(jqXHR.responseText);
});
}, 10000);
});
</script>
</html>
The controller is straightforward as outlined in the question.
#EnableAutoConfiguration
#RestController
public class GreetingController {
#GetMapping(value = "/gJson", produces = MediaType.APPLICATION_JSON_VALUE)
public MyPojo gJson() {
return new MyPojo("Windows 10", System.currentTimeMillis());
}
}
Finally the MyPojo is just a simple two field class.
public class MyPojo {
private String ad;
private long timestamp;
public MyPojo(String ad, long timestamp) {
this.ad = ad;
this.timestamp = timestamp;
}
public String getAd() {
return ad;
}
public void setAd(String ad) {
this.ad = ad;
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
}
I included the timestamp so that you can see the time refreshing every 10 seconds on the web page.
Here I have created dynamic dropdown list using this link, but when I select some value from available list it should be called in action class.
The dropdown list which can be seen in the image ,here the values are loaded dynamically from the database and now what I want is when I select any value from that two dropdown list that values (I mean text value) should be sent to the action class and there I will execute one JDBC select query on the basis of this two values and will display in the table shown in the image but everything should be on load.Action should be on selecting values from dropdown list not on any button click .With static values I am able to call value from dropdown list into action class with name attribute.But in this case I cannot :(
I hope I am clear now .
I have tried calling select tag using listkey,name and id but none of them worked .
Below is my JSP code:
<div>
<div class="invoicetext1">Event Name :</div>
<s:select name="dp.eventState"
list="%{state}"
class="billlistbox1"
id="eventName" />
<div>
<s:select name="dp.companyState"
class="billlistbox2"
listKey="companyState"
list="%{status}">
</s:select>
</div>
<div class="invoicetext2">Company Name :</div>
<div class="clear"></div>
</div>
<s:form action="ActionSelect">
<s:submit value=" Click Here"/>
</s:form>
<div>
Action class for loading dynamic dropdown list :
package com.ca.actions;
import java.sql.Connection;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import com.ca.database.Database;
import com.ca.pojo.Event;
import java.sql.PreparedStatement;
import com.opensymphony.xwork2.ActionSupport;
public class RetrieveEvNaCoNaAction extends ActionSupport {
private static final long serialVersionUID = -5418233715172672477L;
List<Event> dataForBillsJspList;
private List state = new ArrayList();
private List status = new ArrayList();
String eventName;
public String getEventName() {
return eventName;
}
public void setEventName(String eventName) {
this.eventName = eventName;
}
public RetrieveEvNaCoNaAction() {
// TODO Auto-generated constructor stub
}
public List<Event> getDataForBillsJspList() {
return dataForBillsJspList;
}
public void setDataForBillsJspList(List<Event> dataForBillsJspList) {
this.dataForBillsJspList = dataForBillsJspList;
}
public List getStatus() {
return status;
}
public void setStatus(List status) {
try {
Database database = new Database();
Connection con = database.Get_Connection();
PreparedStatement ps = con
.prepareStatement("SELECT EVENT_NAME,COMPANY_NAME,date_format(FROM_DATE,'%d/%m/%Y') as dateAsFrom,date_format(TO_DATE,'%d/%m/%Y') as dateAsTo FROM EVENT");
ResultSet rs = ps.executeQuery();
//dataForBillsJspList = new ArrayList<Event>();
while (rs.next()) {
/*dataForBillsJspList.add(new Event(rs.getString("EVENT_NAME"),
rs.getString("COMPANY_NAME"), rs
.getString("dateAsFrom"), rs
.getString("dateAsTo")));
System.out.println(rs.getString("EVENT_NAME"));*/
status.add(rs.getString("COMPANY_NAME"));
}
System.out.println("Data Collected ...");
}catch(Exception e)
{
e.printStackTrace();
}
}
public List getState() {
return state;
}
#Override
public String execute() throws Exception {
// TODO Auto-generated method stub
setState(this.state);
setStatus(this.status);
return "success";
}
public String showEventDetails(){
System.out.println("Hi.."+eventName);
return SUCCESS;
}
public void setState(List state) {
//implement the application specific logic to
try {
Database database = new Database();
Connection con = database.Get_Connection();
PreparedStatement ps = con
.prepareStatement("SELECT EVENT_ID,EVENT_NAME,COMPANY_NAME,CONTACT_PERSON,CONTACT_NO,EMAIL_ID,EVENT_VENUE,date_format(FROM_DATE,'%d/%m/%Y') as dateAsFrom,date_format(TO_DATE,'%d/%m/%Y') as dateAsTo ,EVENT_TIME FROM EVENT");
ResultSet rs = ps.executeQuery();
dataForBillsJspList = new ArrayList<Event>();
while (rs.next()) {
dataForBillsJspList.add(new Event(rs.getString("EVENT_ID"),rs.getString("EVENT_NAME"),
rs.getString("COMPANY_NAME"),rs.getString("CONTACT_PERSON"),rs.getString("CONTACT_NO"),rs.getString("EMAIL_ID"),rs.getString("EVENT_VENUE"), rs
.getString("dateAsFrom"), rs
.getString("dateAsTo"),rs.getString("EVENT_TIME")));
//System.out.println(rs.getString("EVENT_NAME"));
state.add(rs.getString("EVENT_NAME"));
System.out.println(rs.getString("EVENT_ID"));
}
System.out.println("Data Collected ...");
}catch(Exception e)
{
e.printStackTrace();
}
//Here for displaying the data on UI, we are using few hardcoded values//
}
}
After loading dynamic dropdown list now i am trying to call selected value in action class by S.O.P but it gives null pointer exception. Below is my POJO class:
package com.ca.pojo;
public class Dropdown
{
private String eventState;
private String companyState;
public Dropdown() {
// TODO Auto-generated constructor stub
}
public String getEventState() {
return eventState;
}
public void setEventState(String eventState) {
this.eventState = eventState;
}
public String getCompanyState() {
return companyState;
}
public void setCompanyState(String companyState) {
this.companyState = companyState;
}
}
and below is action class where I am trying to call that selected value by using name attribute :
package com.ca.actions;
import com.ca.pojo.Dropdown;
import com.opensymphony.xwork2.ActionSupport;
public class DropdownAction extends ActionSupport
{
Dropdown dp;
public DropdownAction() {
// TODO Auto-generated constructor stub
}
public Dropdown getDp() {
return dp;
}
public void setDp(Dropdown dp) {
this.dp = dp;
}
#Override
public String execute() throws Exception {
// TODO Auto-generated method stub
System.out.println(dp.getEventState());
return "success";
}
}
struts.xml is properly configured. Now after selecting two values I want to display data in the below table accordingly without any button click but in jsp i have created button just to see whether i am getting the selected value in action class but in actual i want it without any button click.
Well, there is a huge mess here :D
First of all, the NullPointerException is thrown because the values are not sent, and the values are not sent because they're not in the form.
You should enclose them in the form like this for them to be sent to the ActionSelect action:
<s:form action="ActionSelect">
<div class="invoicetext1">Event Name :</div>
<s:select name="dp.eventState"
list="%{state}"
class="billlistbox1"
id="eventName" />
<div>
<s:select name="dp.companyState"
class="billlistbox2"
listKey="companyState"
list="%{status}">
</s:select>
</div>
<div class="invoicetext2">Company Name :</div>
<div class="clear"></div>
</div>
<s:submit value=" Click Here"/>
</s:form>
Solved the mistery, this doesn't solve your problem, though.
You have two main ways to contact actions from a page:
Using a standard submit (as you're doing):
you either submit a form with its content, or call a link by eventually passing parameters in the querystring. This creates a Request, that will contact an action, that will return an entire JSP, that will be loaded in place of the page you're on now.
Using AJAX:
you POST or GET to an action without changing the current page, and the action can return anything, like a JSP snippet, a JSON result, a binary result (through the Struts2 Stream result), etc...
You then can choose what to do with the returned data, for example load it inside a <div> that before was empty, or had different content.
Now your problem is that you're contacting an action that is not the one you're coming from (is not able to re-render the entire JSP you're on) and you're calling it without using AJAX, then whatever the object mapped to the "success" result is (the whole JSP, or a JSP snippet), it will be loaded in place of the JSP you're on, and it will fail.
Since you seem to be quite new to this, I suggest you start with the easy solution (without AJAX), and after being expert with it, the next time try with AJAX.
That said,
avoid putting logic in getters and setters;
avoid calling methods that are not setter as setters (setState, setStatus...);
always make your attributes private;
try giving speaking names to variables: state and status for event states and company states are really confusing; and what about "state" instead of "name" (in jsp and on DB is "name");
consider loading informations like selectbox content in a prepare() method, so they will be available also in case of errors;
you're not closing the connections (and BTW it would be better to use something more evoluted, like Spring JDBC, or better Hibernate, or even better JPA, but for now keep going with the raw queries)
The following is a refactoring of your code to make it achieve the goal. I'll use #Getter and #Setter only for syntactic sugar (they're Lombok annotations, but you keep using your getters and setters, it's just for clarity):
<head>
<script>
$(function(){
$("#event, #company").on('change',function(){
$("#myForm").submit();
});
});
</script>
</head>
<body>
<form id="myForm">
<div>
...
<s:select id="event" name="event" list="events" />
...
<s:select id="company" name="company" list="companies" />
...
</div>
</form>
<div>
...
Table - iterate **dataForBillsJspList** here
...
</div>
</body>
public class RetrieveEvNaCoNaAction extends ActionSupport {
private static final long serialVersionUID = -5418233715172672477L;
#Getter private List<Event> dataForBillsJspList = new ArrayList<Event>();
#Getter private List<String> events = new ArrayList<String>();
#Getter private List<String> companies = new ArrayList<String>();
#Getter #Setter private String event = null;
#Getter #Setter private String company = null;
#Override
public void prepare() throws Exception {
Connection con;
try {
con = new Database().Get_Connection();
// load companies
PreparedStatement ps = con.prepareStatement("SELECT DISTINCT company_name FROM event");
ResultSet rs = ps.executeQuery();
while (rs.next()) { companies.add(rs.getString("company_name")); }
// load events
ps = con.prepareStatement("SELECT DISTINCT event_name FROM event");
rs = ps.executeQuery();
while (rs.next()) { events.add(rs.getString("event_name")); }
} catch(Exception e) {
e.printStackTrace();
} finally {
con.close();
}
}
#Override
public String execute() {
Connection con;
try {
con = new Database().Get_Connection();
// load the table. The first time the table is loaded completely
String sql = "SELECT EVENT_ID, EVENT_NAME, COMPANY_NAME, CONTACT_PERSON, CONTACT_NO, EMAIL_ID, EVENT_VENUE, " +
"date_format(FROM_DATE,'%d/%m/%Y') as dateAsFrom, date_format(TO_DATE,'%d/%m/%Y') as dateAsTo ,EVENT_TIME " +
"FROM event";
String where = "";
// if instead this action has been called from the JSP page,
// the result is filtered on event and company:
if (event!=null && company!=null) {
where = " WHERE event_name = ? AND company_name = ?";
}
// load companies
PreparedStatement ps = con.prepareStatement(sql + where);
if (where.length()>0) {
ps.setString(1,event);
ps.setString(2,company);
}
ResultSet rs = ps.executeQuery();
while (rs.next()) {
dataForBillsJspList.add(new Event(rs.getString("EVENT_ID"),rs.getString("EVENT_NAME"),rs.getString("COMPANY_NAME"),
rs.getString("CONTACT_PERSON"),rs.getString("CONTACT_NO"),rs.getString("EMAIL_ID"),
rs.getString("EVENT_VENUE"), rs.getString("dateAsFrom"), rs.getString("dateAsTo"),
rs.getString("EVENT_TIME")));
}
} catch(Exception e) {
e.printStackTrace();
} finally {
con.close();
}
return SUCCESS;
}
}
It is a kickoff example, but it should work.
The next steps are:
create a POJO with id and description, show the description in the select boxes, but send the id
use header values ("please choose an event"...) and handle in action conditional WHERE (only company, only event, both)
PAGINATION
Good luck
Using Javascript/jQuery you can do this, it depends on what you want to do after reached action class.
If you want to navigate to another page use the code below.
Add onchange event as an attribute to your dropdown,
onchange="customFunction(this.value)"
create customFunction in header part,
function customFunction(selectedValue){
window.location="Action_URL?myValue="+selectedValue;
}
Or if you want to return back the same page use jQuery ajax,
$("#eventName").change(function(e){
var selectedValue = $(this).val();
$.ajax({
type : 'post',
url : 'Action_URL',
data: { myValue: selectedValue},
success : function(data) {
alert(data);
console.log(data);
}
});
});
Hope this helps.
This is my code
function sendMessage()
{
if(textMessage.value!=="close")
{
if(searchid==="John" && login_id==="Mary" || searchid==="Mary" && login_id==="John")
{
webSocket.send(textMessage.value);
textMessage.value="";
}
}
else
{
webSocket.close();
}
}
I am making a chat application and getting response from server.Firstly the server was sending response to all the clients connected to it.But now I am converting it into one to one client based chat but the problem is if john is chatting with mary these values are placed in database and I can only one time get the data from database via scriplet when page is loaded so how to implement it when user want to chat with say dave.Then I can't get the values from database.
I totally understand that you would like to write this by your self, but there are lots of frameworks out there that will help you with the complex stuff and let you focus on the actuall business issues to solve.
We use XSockets.NET most of the time since that is perfect for our needs.
Setting ap a one to one chat (or other scenarios) is very easy with XSockets since it is all about publish/subscribe... And you can also filter where to send messages on the server with powerful extension methods
A simple sample chat:
To save some time and keep it stupid and simple I will use two dropdowns where you select your name and the city you are in. So not actually 1-1, but it is so that you would get the concept.
JAVASCRIPT/MARKUP
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script src="Scripts/jquery-2.1.0.js"></script>
<script src="Scripts/moment.js"></script>
<script src="Scripts/XSockets.latest.js"></script>
<script src="Scripts/knockout-3.1.0.js"></script>
<script>
//viewmodel for our messages
var vm = {
messages : ko.observableArray([])
}
//xsockets connection
var conn;
$(function() {
ko.applyBindings(vm);
//Connect to our controller (Chat)
conn = new XSockets.WebSocket('ws://127.0.0.1:4502/Chat');
conn.onopen = function() {
//open, set city and username (for demo only)
conn.setProperty("UserName", $('#username').val());
conn.setProperty("City", $('#cities').val());
//listen for chatmesages
conn.on('chatmessage', function (d) {
//Add message to viewmodel
vm.messages.push(d);
});
}
//When we hit enter, send a message
$('input').on('keydown', function (e) {
if (e.keyCode == 13) {
//Build message, we do not need to set From since the server know who I am
var message = { Text: $(this).val(), Time: moment().format('MMMM Do YYYY, h:mm:ss a') };
conn.publish('chatmessage', message);
}
});
//When City or Username is changed, tell the server
$('#cities').on('change', function(d) {
conn.setProperty("City", $(this).val());
});
$('#username').on('change', function (d) {
conn.setProperty("UserName", $(this).val());
});
});
</script>
</head>
<body>
<input type="text" placeholder="type here, enter to send"/>
<select id="username">
<option value="steve">steve</option>
<option value="ben">ben</option>
<option value="tomas">tomas</option>
</select>
<select id="cities">
<option value="london">london</option>
<option value="paris">paris</option>
<option value="tokyo">tokyo</option>
</select>
<div data-bind="foreach:messages">
<h5 data-bind="text:From + ' - ' + Time"></h5>
<div data-bind="text:Text"></div>
</div>
</body>
</html>
C#
using XSockets.Core.XSocket;
using XSockets.Core.XSocket.Helpers;
namespace SimpleChat
{
public class ChatMessage
{
public string From { get; set; }
public string Text { get; set; }
public string Time { get; set; }
}
public class Chat : XSocketController
{
/// <summary>
/// My name, we set this from javascript...
/// </summary>
public string UserName { get; set; }
/// <summary>
/// We only send to people being in the same city, we set it from javascript
/// </summary>
public string City { get; set; }
/// <summary>
/// A user sends a message
/// </summary>
/// <param name="chatMessage"></param>
public void ChatMessage(ChatMessage chatMessage)
{
chatMessage.From = this.UserName;
//Send only to the client(s) being in the same city, but you can ofcourse change ot to another user only etc
this.SendTo(p => p.City == this.City, chatMessage,"chatmessage");
}
}
}
Summary
The only thing I did except the code above was to create a new project and then
Install XSockets (to start a xsockets server)
Install XSockets.JsApi (for publish subscribe over websockets)
Install jQuery (becasue I am lazy)
Install Momoent.JS (for working wiht dates in javascript)
Install knockoutjs (for modelbinding)
Added a XSockets bootstrapper into App_Start (found under Add->NewItem->XSockets->XSockets.Web.Bootstrapper
I guess you simply need to add control functionality to your program:
Add two listboxes and two buttons for picking sender, receiver (search_id,log_id)
List <string> logins=new List<string>();
List <string> search=new List<string>();
........
logins.Add("John");
logins.Add("Mary");
.....
search.Add("Dave");
listBox1.Datasource=logins;
listBox2.Datasource=search;
private void button1_Click(object sender, EventArgs e) //pick login_id
{
login_id_to_Compare=listBox1.SelectedValue.ToString();
}
private void button2_Click(object sender, EventArgs e) //pick searcid
{
searchid_to_Compare=listBox2.SelectedValue.ToString();
}
function sendMessage()
{
if(textMessage.value!=="close")
{
if((searchid===searchid_to_Compare) && (login_id===login_id_to_Compare))
{
webSocket.send(textMessage.value);
textMessage.value="";
}
}
else
{
webSocket.close();
}
}
Your send message seems too simplistic. There is not enough info for the server to route the message to the correct destination.
You would need to send along with the message the destination so your server can route the message to the correct user.
In your db you then can save the "to" and "from" and display the correct messages for only the parties involved.
You would of course have to add the fields to your chat program to select the destination.
function sendMessage(from, to, msg)
{
webSocket.send("{'from':" + from + ", 'to':" + to + ", 'msg': " + msg + "}");
}
I am trying to fill the table with both column headers and its body with data, however it fails to make the ajax call if.
<table id="datatable1" cellpadding="0" cellspacing="0" border="0" class="display" width="100%">
<thead>
</thead>
<tbody>
</tbody>
</table>
I leave both the head and body empty.
But adding some random title.
<thead>
<tr>
<th>Random column title</th>
</tr>
</thead>
fixes it. Though I mean to add both the column names and the data at the same time from a JSON string and add it to the table it won't let me :
I am also able to load stuff from the database no problem if the proper aoColumns and mData are established beforehand.
var oTable; //datatable reference
var start = 0; //first row's id to load
var qty = 100; //number of rows to load
var DESC = "false"; //load last row first and go down?
var type = "something";
var ajaxURL = GLOBAL_ROUTE + "api/application/datatable/fillTable/" + type + "/" + start + "/" + qty + "/" + DESC;
oTable = $('#datatable1').dataTable({
"sPaginationType" : "full_numbers",
"sDom" : '<"top"<"length"l><"search"f><"position">>rt<"bottom"<"info"i><"pages"p>>',
"bProcessing" : false,
"bServerSide" : false,
"sAjaxSource" : ajaxURL,
"bDeferRender" : true,
/*"aoColumns" : [ {
"mData" : "a"
}, {
"mData" : "b"
}, {
"mData" : "c"
}, {
"mData" : "d"
} ]*/
});
alert("asasd"); //this alert is not even reached if no header/body/aoColumns are set.
Any way around this without making an ajax call beforehand with the column names?
Nvm, I found the way and I'll share it with ya!
All I had to do was change the way I was making the ajax call. Instead of using the datatables "sAjaxSource" parameter to do it, I made my own jquery $.ajax() call to load absolutely everything via json.
First I changed the js code:
$.ajax({
"url" : ajaxURL,
"success" : function(json) {
json.bDestroy = true;
json.sPaginationType = "full_numbers";
json.sDom = '<"top"<"length"l><"search"f><"position">>rt<"bottom"<"info"i><"pages"p>>';
oTable = $('#datatable1').dataTable(json);
},
"dataType" : "json"
});
Then I had to make some changes on the data table object.
Here's the java code :
import java.util.List;
public class DataTableObject {
String sPaginationType = "";
String sDom = "";
boolean bProcessing = false;
boolean bServerSide = false;
String sEcho;
int iTotalRecords;
private List<Object> aoColumns;
List<Object> aaData;
public String getsPaginationType() {
return sPaginationType;
}
public void setsPaginationType(String sPaginationType) {
this.sPaginationType = sPaginationType;
}
public String getsDom() {
return sDom;
}
public void setsDom(String sDom) {
this.sDom = sDom;
}
public boolean isbProcessing() {
return bProcessing;
}
public void setbProcessing(boolean bProcessing) {
this.bProcessing = bProcessing;
}
public boolean isbServerSide() {
return bServerSide;
}
public void setbServerSide(boolean bServerSide) {
this.bServerSide = bServerSide;
}
public int getiTotalRecords() {
return iTotalRecords;
}
public void setiTotalRecords(int iTotalRecords) {
this.iTotalRecords = iTotalRecords;
}
public String getsEcho() {
return sEcho;
}
public void setsEcho(String sEcho) {
this.sEcho = sEcho;
}
public List<Object> getAaData() {
return aaData;
}
public void setAaData(List<Object> aaData) {
this.aaData = aaData;
}
public List<Object> getAoColumns() {
return aoColumns;
}
public void setAoColumns(List<Object> aoColumns) {
this.aoColumns = aoColumns;
}
}
So yeah, apparently I had to make an outside ajax call, but not two as I thought I might have to do in the end.
Hope this might be of help to someone in the future :)
K, back to work.
Since you're using Java on the back end, instead of playing with workarounds, you might want to consider the many examples provided on the JED website that demonstrate how best to work with DataTables on the Java platform. Check out: http://jed-datatables.net