I have a servlet that gets parameters from an HTML dropdown page. On button click the data is sent to the servlet. It works the first time the data is sent, but if I stay on the page and select a different value from the dropdown
and click the submit button, the new data is not set into the session variable.
My servlet is below. Do I need to modify the DoGet method? Again, it works the first time but the session variable doesn't change afterwards.
#WebServlet("/ListStudentServlet")
public class ListStudentServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public ListStudentServlet() {
super();
// TODO Auto-generated constructor stub
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String sessid = request.getParameter("studentid");
ArrayList<FactStudentDataBean> result = new ArrayList<>();
try ( Connection con = JdbcUtil.getConnection()) {
String sql= "select F.Sessionid "
+ "from FACT_STUDENT F "
+ "where studentid = '"+sessid+"';";
try (Statement st = con.createStatement()) {
ResultSet rs = st.executeQuery(sql);
while (rs.next()){
result.add(new FactStudentDataBean(rs.getString(1)));
}
for (FactStudentDataBean factStudentDataBean : result) {
sessid = factStudentDataBean.getSessid();
}
} catch (Exception e) {
e.printStackTrace();
}
}
catch (Exception e) {
e.printStackTrace();
}
//Trying to set the session variable below, works the first time but anything after doesn't change
HttpSession session = request.getSession(true);
session.setAttribute("sessid", sessid);
}
}
Your code is a little bit "dirty". First of all: why you are writing this sql query like this?:
String sql= "select F.Sessionid "
+ "from FACT_STUDENT F "
+ "where studentid = '"+sessid+"';";
and not like this?:
String sql= "select F.Sessionid from FACT_STUDENT F where studentid = '"+sessid+"';";
Second: Always try to use prepareStatement instead of createStatement (for explanation of what i am telling please see this question:prepareStatement vs executeStatement)
And for the answer now: Ithink you must use session.getAttribute("sessid", sessid);
Check the jsessionid values you are getting on server side. If both are different then try to get session by passing false instead of true.
request.getSession(false);
Also goto tomcat manager application and monitor active sessions.
Hope this will help.
Related
I get the json value using the retrofit library at application launch and I want to send it to the global variable in the class. How can I do it?
Domain is coming, I can see it on the screen with toast message
public void onCreate() {
setRetrofitSettings();
}
public void setRetrofitSettings(){
retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
timeApi = retrofit.create(TimeApi.class);
timeTurkeyCall = timeApi.getTime();
timeTurkeyCall.enqueue(new Callback<TimeTurkey>() {
#Override
public void onResponse(Call<TimeTurkey> call, Response<TimeTurkey> response) {
if (response.isSuccessful()){
timeTurkey = response.body();
Global.APIURL = String.valueOf(timeTurkey.getDateTime());
// I want to send the value here.
}
}
#Override
public void onFailure(Call<TimeTurkey> call, Throwable t) {
System.out.println(t.toString());
}
});
}
I want to send post value to global class
I want the incoming data to be assigned to the API_URL variable from here
public class Global {
public static final String API_URL;
}
I want the incoming domain to be active as long as the application is open.
I’m trying to upload an excel in servlet and process it. While uploading I set enctype=“multipart/form-data” in my form. But in my servlet .isMultiPart(request) returns false.
JSP code:
function fSubir()
{
fFreezeButtons();
this.document.forms[0].action="../servlet/renault.saf.demandepiece.demandes.servlet.AjouterPoste";
if (this.document.forms[0].Flag.value == "1")
{
this.document.forms[0].Flag.value = "0";
this.document.forms[0].submit();
}
}
Select .xlsx type File :
<input type="submit" value="upload" onclick="fSubir()"/>
My .Jsp also has another form of get method which doesn’t have any enctype.
Servlet code;
public class AjouterPoste extends SapprServlet{
/**
*
*/
private static final long serialVersionUID = 1L;
private final String UPLOAD_DIRECTORY = "/appli01/safdev01/saf_cl2/test/";
public void performTask(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
System.out.println("inside the AjouterPoste class - performTask");
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
System.out.println("Inside doPost:"+isMultipart+":"+request);
Please find the parts of my code on which I’m trying to upload a file.
When you submit a form having multipart/form-data, you can't use request.getParameter(paramName). Instead use the code below (part of the Apache FileUpload library)
try {
List<FileItem> items = new ServletFileUpload(new DiskFileItemFactory()).parseRequest(request);
for (FileItem item : items) {
if (item.isFormField()) {
// this part is used instead of request.getParameter
String fieldName = item.getFieldName();
String fieldValue = item.getString();
// do something here
} else {
// this is the file processing part
String fieldName = item.getFieldName();
String fileName = FilenameUtils.getName(item.getName());
InputStream fileContent = item.getInputStream();
...
}
}
} catch (FileUploadException e) {
throw new ServletException("exception", e);
}
You can tell that a specific item is a regular form item (and not a file) by checking that FileItem.isFormField() method returns true.
So my project demonstrates the results of a k-means clustering algorithm using servlets.
When I cluster for the first time, everything works well and my program relocates the user to the results.jsp page.
But because k-means is a bit random at selecting centroids, I added a re-cluster feature in my code in the results.jsp which re-clusters my data with the settings originally used.
My servlet code for re-clustering looks like this:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
do stuff...
//reload results page
String htmlResponse = "<html><header><meta http-equiv=\"refresh\" content=\"0; URL='results.jsp\" /></header></html>";
writer.println(htmlResponse);
//but this doesnt work...
}
So after the clustering is done, I want to reload the resutls.jsp page. I tried adding a JavaScript to my jsp page since refresh is a client side operation. But the problem with that approach is that refresh happens before the clustering is fully completed. So I get Exceptions when trying to print the results. Any advice?
My refresh script looks like this:
<script type="text/javascript">
function refresh() {
location.reload(true);
}
</script>
<script type="text/javascript">
function reCluster(cluster_id) {
recluster();
}
</script>
and on the .jsp i'm calling this like this:
<form class="form-horizontal" action="generateArff" method="GET" enctype="multipart/form-data">
<button type="button" class="btn btn-default btn-lg" onclick="reCluster(); refresh();">
<span class="glyphicon glyphicon-refresh"></span> Re-Cluster
</button>
<button type="submit" class="btn btn-info btn-lg">
<span class="glyphicon glyphicon-download"></span> Generate file
</button>
</form>
Can you advice on the matter?
So, #MarcoBolis provided a very good and informative answer, and definitely gets a +1 from me.
However, I think that the most simple solutions are the most effective ones.
As I see your code, I can only assume that you are using an AJAX request to your servlet because I see 1 html form with 2 buttons that do different things. So, what I would do, is go to your ReClusterServlet and add the following:
public class ReClusterServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter writer = response.getWriter();
//Call your Cluster class and methods...
//wait for it...
//return something to your AJAX call.
writer.print("refresh page");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
now, go to your AJAX request.
I assume it will be in the recluster() function I see you are calling in the head of your http code.
so it must be something like this:
function recluster() {
$.ajax({
url:'ReClusterServlet',
type:'POST'
});
}
This thing, is calling the servlet but did you know that when your servlet was done with the computation it returned a success message to it??? But you are ignoring it!!!
it's this line writer.print("refresh page");
Now re-write the function as follows:
function recluster() {
$.ajax({
url:'ReClusterServlet',
type:'POST',
success:function() { //handle the successful return by reloading the current page
location.reload();
}
});
}
Again, these are speculations because they seem a bit incomplete, so feel free to correct me if I'm wrong, but I have a strong feeling that you need to study a bit more on the client-server architecture, JQuery and AJAX
I understand you are issuing an AJAX call to the server to start an asynchronous task, performing the clustering.
You could notify the client of task completion by means of a message returned through the XHR:
function reCluster() {
var xhr = new XMLHttpRequest();
xhr.open('GET', 'ReClusterServlet', true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
// Refresh if everything went OK
if (xhr.responseText === 'Done') refresh();
}
};
}
The tricky part is handling the notification Java-side.
If you are using Servlet API 3.x+, then you are lucky: just make your request an async one:
public class ReClusterServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// Defer the request to this HTTP request to later
AsyncContext asyncCtx = request.startAsync(request, response);
asyncCtx.setTimeout(0);
// Start the long running computation in another thread,
// passing the AsyncContext
new MyLongRunningTask(asyncCtx).start();
}
}
Then complete it in the other thread:
public class MyLongRunningTask {
private final AsyncContext asyncCtx;
public MyLongRunningTask(AsyncContext asyncCtx) {
this.asyncCtx = asyncCtx;
}
// ...
private void finish() {
// Send the response asynchronously
Writer out = this.asyncCtx.getResponse().getWriter();
out.println("Done");
out.flush();
this.asyncContext.complete();
}
}
If instead you are using an older version of the Servlet API, you will have to make the serving thread (the one on which the doGet method gets called) block until the computation is finished.
If you have a reference to the thread on which the computation is performed available, you can call its join method to await termination:
public class ReClusterServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Thread async = new MyLongRunningThread();
async.start();
// Await end of computation
try {
async.join();
} catch (InterruptedException e) {
// Computation was interrupted...
}
response.getWriter().println("Done");
}
}
If instead the computation task is queued for execution, for example by an ExecutorService, you have to use wait/notify:
public class ReClusterServlet extends HttpServlet {
private ExecutorService executor;
// ...
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
MyLongRunningRunnable task = new MyLongRunningRunnable();
synchronized (task) {
executor.execute(task);
// Put current thread to sleep until task is no more RUNNING
// (assuming state is a property of MyLongRunningRunnable)
while (task.getState() == State.RUNNING) {
try {
task.wait();
} catch (InterruptedException e) {
// Computation was interrupted...
}
}
}
response.getWriter().println("Done");
}
}
Assuming that the async task calls notify when done:
public class MyLongRunningRunnable implements Runnable {
private State state = State.RUNNING;
// ...
private synchronized void finish() {
this.state = State.DONE;
this.notify();
}
}
NOTE that these two solutions that block the request thread may cause performance issues if you have lots of incoming requests and the clustering job takes very long.
so a quick overview of what I'm doing
I am using Android Webview to Render JavaScript and then reading the HTML from the javascript to parse it.
I am currently having trouble with retrieving the HTML from a website called Sport Chek.
Here is the code for my SportChekSearch class:
public class SportChekSearch extends SearchQuery{
public Elements finalDoc;
private ArrayList<Item> processed;
private final Handler uiHandler = new Handler();
public int status = 0;
//This basically is just so that the class knows which Activity we're working with
private Context c;
protected class JSHtmlInterface {
#android.webkit.JavascriptInterface
public void showHTML(String html) {
final String htmlContent = html;
uiHandler.post(
new Runnable() {
#Override
public void run() {
Document doc = Jsoup.parse(htmlContent);
}
}
);
}
}
/**
* Constructor method
* #param context The context taken from the webview (So that the asynctask can show progress)
*/
public SportChekSearch(Context context, String query) {
final Context c = context;
try {
final WebView browser = new WebView(c);
browser.setVisibility(View.INVISIBLE);
browser.setLayerType(View.LAYER_TYPE_NONE, null);
browser.getSettings().setJavaScriptEnabled(true);
browser.getSettings().setBlockNetworkImage(true);
browser.getSettings().setDomStorageEnabled(true);
browser.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
browser.getSettings().setLoadsImagesAutomatically(false);
browser.getSettings().setGeolocationEnabled(false);
browser.getSettings().setSupportZoom(false);
browser.getSettings().setUserAgentString("Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36");
browser.addJavascriptInterface(new JSHtmlInterface(), "JSBridge");
browser.setWebViewClient(
new WebViewClient() {
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
}
#Override
public void onPageFinished(WebView view, String url) {
browser.loadUrl("javascript:window.JSBridge.showHTML('<html>'+document.getElementsByTagName('html')[0].innerHTML+'</html>');");
}
}
);
browser.loadUrl("https://www.sportchek.ca/search.html#q=" + query.replaceAll(" ", "+") + "&lastVisibleProductNumber=3");
browser.loadUrl(browser.getUrl());
final String link = browser.getUrl();
new fetcher(c).execute(link);
}
catch(Exception e){
e.printStackTrace();
}
//Get the link from the WebView, and save it in a final string so it can be accessed from worker thread
}
/**
* This subclass is a worker thread meaning it does work in the background while the user interface is doing something else
* This is done to prevent "lag".
* To call this class you must write fetcher(Context c).execute(The link you want to connect to)
*
*/
class fetcher extends AsyncTask<String, Void, Elements> {
Context mContext;
ProgressDialog pdialog;
public fetcher(Context context) {
mContext = context;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
pdialog = new ProgressDialog(mContext);
pdialog.setTitle(R.string.finding_results);
pdialog.setCancelable(false);
pdialog.show();
}
//This return elements because the postExecute() method needs an Elements object to parse its results
#Override
protected Elements doInBackground(String... strings) {
//You can pass in multiple strings, so this line just says to use the first string
String link = strings[0];
//For Debug Purposes, Do NOT Remove - **Important**
System.out.println("Connecting to: " + link);
try {
doc = Jsoup.connect(link)
.ignoreContentType(true)
.userAgent("Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36")
.timeout(10000)
.get();
finalDoc = doc.select("body section.product-grid-wrapper");
System.out.println(finalDoc.toString());
} catch (IOException e) {
e.printStackTrace();
}
return finalDoc;
}
#Override
protected void onPostExecute(Elements result) {
//This line clears the list of info in the Search activity
//I should probably be using a getter method but adapter is a static variable so it shouldn't matter
//parse seperates document into elements
//crunch results formats those elements into item objects
//I am saving the result of this to an ArrayList<Item> called "processed"
processed = crunchResults(result);
//For debug purposes, do NOT remove - **Important**
System.out.println(processed.size() + " results have been crunched by Sport Chek.");
//Adds all of the processed results to the list of info in Search activity
ClothingSearch.adapter.addAll(processed);
//For debug purposes, do NOt remove - **Important
System.out.println("Adapter has been notified by Sport Chek.");
//Closes the progress dialog called pdialog assigned to the AsyncTask
pdialog.dismiss();
ClothingSearch.adapter.notifyDataSetChanged();
SearchQueueHandler.makeRequest(mContext, processed, SearchQueueHandler.CLOTHING_SEARCH);
}
}
public ArrayList<Item> crunchResults(Elements e){
ArrayList<Item> results = new ArrayList<Item>();
try {
for (int i = 0; i < e.size(); i++) {
Element ele = e.get(i);
String link = "https://www.sportchek.ca" + ele.select(" a.product-grid__link").attr("href");
System.out.println("https://www.sportchek.ca" + ele.select(" a.product-grid__link").attr("href"));
String title = ele.select(" span.product-title-text").text();
String pricestring = ele.select(" span.product-price__wrap").text();
price = Double.parseDouble(pricestring.substring(pricestring.lastIndexOf("$")));
System.out.println(pricestring);
//*******************************************
String store = "Sport Chek";
//Adds the formatted item to an ArrayList of items
results.add(new Item(title, store, price, link));
//Prints the object's to String to console
//For debug purposes, do NOT remove - **Important
System.out.println(results.get(i).toString());
}
} catch (Exception a){
a.printStackTrace();
}
return results;
}
public int getStatus(){
return status;
}
}
The two relevant methods are doInBackground in my AsyncTask and the crunchResults method.
Here is the result I get from using Ctrl+Shift+I on the actual website (Desired Result):
But when running the above code and using a println here is the result that I get for the tag section class="product-grid-wrapper" :
<section class="product-grid-wrapper">
<ul data-module-type="SearchProductGrid" class="product-grid__list product-grid__list_quickview">
<!-- #product-grid__item-template -->
</ul>
</section>
Can anyone help me figure out why I am not getting my desired result?
All help is appreciated
EDIT: for this specific search that the println data was collected from, the link was https://www.sportchek.ca/search.html#q=men+coat&lastVisibleProductNumber=3
It looks like what you are actually getting is the actual html sent by the server, and that your 'desired result' is what the DOM looks like after the JavaScript runs.
Your 'actual' is what I see if I use "View Source" in Chrome, while your "desired result" is what I see if I use Chrome's DOM inspector.
On further inspection, I see that you are not actually getting the HTML from the browser, you are (indirectly) using JSoup's Connection object to get the HTML directly. Unfortunately, that's not going to run the Javascript.
Instead, you're going to have to get the HTML from the WebView after the JavaScript runs. For a possible way to do that, see How do I get the web page contents from a WebView?
Then, you give the HTML that you get from that to JSoup with
Jsoup.parse(html);
I've looked in a variety of places for an answer to my query, but nothing has helped me thus far. I'm currently trying to learn Android development, and i'm stuck on how to sort a list alphabetically. I am using this tutorial on how to create the list and have modified parts of the "Albums" page to suit my needs, from albums to artists (i'm still working on this, just wanting the sorting finished before changing it fully). This particular list calls on a file from a HTTP address when the app is accessed to check it for updates.
Here is the code from that particular page, minus all the imports:
public class AlbumsActivity extends ListActivity {
// Connection detector
ConnectionDetector cd;
// Alert dialog manager
AlertDialogManager alert = new AlertDialogManager();
// Progress Dialog
private ProgressDialog pDialog;
// Creating JSON Parser object
JSONParser jsonParser = new JSONParser();
ArrayList<HashMap<String, String>> albumsList;
// albums JSONArray
JSONArray albums = null;
// albums JSON url
private static final String URL_ALBUMS = "http://api.androidhive.info/songs/albums.php";
// ALL JSON node names
private static final String TAG_ID = "id";
private static final String TAG_NAME = "name";
private static final String TAG_SONGS_COUNT = "songs_count";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_albums);
cd = new ConnectionDetector(getApplicationContext());
// Check for internet connection
if (!cd.isConnectingToInternet()) {
// Internet Connection is not present
alert.showAlertDialog(AlbumsActivity.this, "Internet Connection Error",
"Please connect to working Internet connection", false);
// stop executing code by return
return;
}
// Hashmap for ListView
albumsList = new ArrayList<HashMap<String, String>>();
// Loading Albums JSON in Background Thread
new LoadAlbums().execute();
// get listview
ListView lv = getListView();
/**
* Listview item click listener
* TrackListActivity will be lauched by passing album id
* */
lv.setOnItemClickListener(new android.widget.AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View view, int arg2,
long arg3) {
// on selecting a single album
// TrackListActivity will be launched to show tracks inside the album
Intent i = new Intent(getApplicationContext(), TrackListActivity.class);
// send album id to tracklist activity to get list of songs under that album
String album_id = ((TextView) view.findViewById(R.id.album_id)).getText().toString();
i.putExtra("album_id", album_id);
startActivity(i);
}
});
}
/**
* Background Async Task to Load all Albums by making http request
* */
class LoadAlbums extends AsyncTask<String, String, String> {
/**
* Before starting background thread Show Progress Dialog
* */
#Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(AlbumsActivity.this);
pDialog.setMessage("Listing Artists...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
pDialog.show();
}
/**
* getting Albums JSON
* */
protected String doInBackground(String... args) {
// Building Parameters
List<NameValuePair> params = new ArrayList<NameValuePair>();
// getting JSON string from URL
String json = jsonParser.makeHttpRequest(URL_ALBUMS, "GET",
params);
// Check your log cat for JSON reponse
Log.d("Albums JSON: ", "> " + json);
try {
albums = new JSONArray(json);
if (albums != null) {
// looping through All albums
for (int i = 0; i < albums.length(); i++) {
JSONObject c = albums.getJSONObject(i);
// Storing each json item values in variable
String id = c.getString(TAG_ID);
String name = c.getString(TAG_NAME);
String songs_count = c.getString(TAG_SONGS_COUNT);
// creating new HashMap
HashMap<String, String> map = new HashMap<String, String>();
// adding each child node to HashMap key => value
map.put(TAG_ID, id);
map.put(TAG_NAME, name);
map.put(TAG_SONGS_COUNT, songs_count);
// adding HashList to ArrayList
albumsList.add(map);
}
}else{
Log.d("Albums: ", "null");
}
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
/**
* After completing background task Dismiss the progress dialog
* **/
protected void onPostExecute(String file_url) {
// dismiss the dialog after getting all albums
pDialog.dismiss();
// updating UI from Background Thread
runOnUiThread(new Runnable() {
public void run() {
/**
* Updating parsed JSON data into ListView
* */
ListAdapter adapter = new SimpleAdapter(
AlbumsActivity.this, albumsList,
R.layout.list_item_albums, new String[] { TAG_ID,
TAG_NAME, TAG_SONGS_COUNT }, new int[] {
R.id.album_id, R.id.album_name, R.id.songs_count });
// updating listview
setListAdapter(adapter);
}
});
}
}
}
My problem is that I have no real idea where I need to put the Collections.sort command. I have tried in so many places, but cannot get it working. No matter where I put the command, it always sorts in order of ID. This is the full code I have for that:
Collections.sort(params, new Comparator<NameValuePair>() {
#Override
public int compare(NameValuePair art1, NameValuePair art2) {
//here getTitle() method return app name...
return art1.getName().compareToIgnoreCase(art2.getName());
}
});
If I try to have return art1.name.compareToIgnoreCase(art2.name); it comes back with an error that says name cannot be resolved or is not a field. I'm really stumped. I thought a list might be a good way to start learning to develop for Android, but now i'm finding this incredibly hard.
Any help would be greatly appreciated.