Pass get values to method and call in jsp page - spring

I'm using spring mvc, making a small web-app.
I have a form in a jsp page, and I'm trying to pass the values from my .GET controller to a method and display the results from the called method after pressing the "Submit" button on the same JSP page or another, preferrably on the same page.
This is how the form looks like:
http://i65.tinypic.com/6gyo02.png
This is the method I want to be called after getting the values from the form:
public void calcMacros() {
int goal = 0;
if (this.goal == 0.7){
goal = 1;
} else if (this.goal == 0.9) {
goal = 2;
} else if (this.goal == 1) {
goal = 3;
} else if (this.goal == 1.2){
goal = 4;
}
switch (goal) {
case 1: weightLoss();
weightLossProtCalc();
weightLossCarbCalc();
weightLossFatCalc();
break;
case 2: weightLoss();
weightLossProtCalc();
weightLossCarbCalc();
weightLossFatCalc();
break;
case 3: tdeeCalculator();
maintainProteinCalc();
maintainCarbCalc();
maintainFatCalc();
break;
case 4: weightGain();
weightGainProtCalc();
weightGainCarbCalc();
weightGainFatCalc();
break;
default:
break;
}
System.out.println("selected goal was " + goal + "and proper methods have been called.");
}
Best question would be, how can I transform this method into a .POST controller so I can display it's results in the same JSP page. Also how do I call this method/controller in the JSP page?
Thank you!
Edit: Controller
#RequestMapping(value = "/calculator" , method = RequestMethod.GET)
public String calculatorPage(ModelMap model, MacroCalculatorForm macroCalculatorForm) {
model.addAttribute("user",getPrincipal());
macroCalculatorForm.calcMacros();
return "calculator";
}
Would this do it, or should I rewrite the method I want to get called into this controller?

You should have two methods in your #Controller:
(1) One method which supports GET : This is to provide the display View of the first page (before the calculations).
(2) One method which supports POST: This is to process the inputs received from the first page and then sending the results to the View (JSP) back.

Reading values from GET requests is easy. It's only need to define parameters with input names as following for age example :
#RequestMapping(value = "/calculator" , method = RequestMethod.GET)
public String calculatorPage(ModelMap model,
MacroCalculatorForm macroCalculatorForm,
#RequestParam(value = "age") int age)
{
//Now you can use age value in your method
model.addAttribute("user",getPrincipal());
macroCalculatorForm.calcMacros();
return "calculator";
}

Related

ASP.NET Web API - Swagger , create multiple views

I am using Swagger with ASP.NET Web API application. If I visit URL http://localhost:5000/swagger
Swagger list all the controllers and actions defined in these controllers. Lets say I have five controllers and each controller has one action. I want to create multiple views such that when
user says http://localhost:5000/swagger/v1 he gets to see all controllers
when user says http://localhost:5000/swagger/v2 he gets to see only one controller
when user says http://localhost:5000/swagger/v3 he gets to see only two controller
Basically I am trying to restrict access to controller via swagger. Based on user requirement, I will share specific URL with them.
Is it possible to achieve this with Swagger?
Yes, you can do exactly what you want.
You should do the following steps:
Create a class that inherits from IDocumentFilter and register it in SwaggerConfig.cs as follows c.DocumentFilter<HideSwaggerEndpointsDocumentFilter>();
Example:
public class HideSwaggerEndpointsDocumentFilter : IDocumentFilter
{
public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer)
{
//enter code here
}
}
This filter is loaded once you load the swagger page. Inside it, you have control over each and every controller action. You can delete some actions based on any criteria decided by you.
Deleting them is a bit tricky, I do it as follows:
foreach (var apiDescription in apiExplorer.ApiDescriptions)
{
var route = "/" + apiDescription.RelativePath.Substring(0, (apiDescription.RelativePath.IndexOf('?') != -1) ? apiDescription.RelativePath.IndexOf('?') : apiDescription.RelativePath.Length).TrimEnd('/');
var path = swaggerDoc.paths[route];
switch (apiDescription.HttpMethod.Method)
{
case "DELETE": path.delete = null; break;
case "GET": path.get = null; break;
case "HEAD": path.head = null; break;
case "OPTIONS": path.options = null; break;
case "PATCH": path.patch = null; break;
case "POST": path.post = null; break;
case "PUT": path.put = null; break;
default: throw new ArgumentOutOfRangeException("Method name not mapped to operation");
}
if (path.delete == null && path.get == null &&
path.head == null && path.options == null &&
path.patch == null && path.post == null && path.put == null)
{
swaggerDoc.paths.Remove(route);
}
}
Disclaimer:
If you put the above code in your DocumentFilter class it will delete all actions regardless of the given URL.
So we are in the final step, where you basically do your desired logic.
Inside the (foreach (var apiDescription in apiExplorer.ApiDescriptions)) you can play and do your custom logic. You have access to HttpContext.Current, so you can get the current URL.
If you don't want to delete the current action have something like this, before the swaggerDoc.paths.Remove(route);.
bool forDelete = false; // your custom logic when it should be deleted
if (!forDelete)
{
return;
}
Hope this helps you.

To create a session explicitly for first the first time page loads in Grails

As soon as a page loads, it renders a lot of data and shows on the view which sort of slows down the performance. I want to restrict this and load the data only when a filter is applied .
I need a way in which a session variable can store the value on the 1st login and no data should be loaded in that 1st session i.e. when any user loads it for the very first time using his login. something like the below in the controller class:
if(session.dtstartDate && session.dtstartDate != '')
{
SimpleDateFormat nsdf = new SimpleDateFormat('yyyy-MM-dd')
Date startDateValue = nsdf.parse(session.dtstartDate.substring(0, session.dtstartDate.lastIndexOf("T")))
eq("startDate", startDateValue)//if any filter is applied
}
else{
if this is the 1st session the startdate should be null --> need a piece of code to be replaced here
}
I am unsure maybe I still have not got what you have tried to ask properly, I thought I should try to answer your question to how I understood your problem to be.
If we take this basic filter and add some stuff to it we may be able to get to what you wish to do using a better method ? I am unsure what startDate is actually representing but if we base it on if a user has hit a controller for the first time or not the answer would be something like this, you could replace the logic to startDate if it has other significance:
so adding some hashmap arrayset to your filter that gets called before the action is called when user clicks the controller/action:
in your conf/MyFiters.groovy
class MyFilters {
static final Set<HashMap<String[],String[]>> userControl =
([:] as Set).asSynchronized()
//where controller is controllerName and action is actionName
def filters = {
MyLogger() {
before = {
if (verifyClientMaster(session.id as String ,controllerName)==false) {
clientMaster.add(session.id as String:controllerName)
// now here you have a new user so set
// some session value for gsp or load something
//according
}else{
// user has hit it before do something else or set something else
}
}
}
}
}
Boolean verifyClientMaster(String sessionId,String controller) {
// iterate
boolean found = false
userControl.each { k,v -> if (k == sessionId && v == controller) {
found = true
}
}
}
something like this and you know if the user has hit the controller or not.. remember the session is per user. so a new user has a new session entity.
Hope it is of help and not off track..
E2A
Thinking about it you do go down this route then you would need to keep track of when session expires and to remove the user from clientMaster.. take a look at this project if you did go down this route.. personally I would even do it simpler than this... on a rethink...
class MyFilters {
def filters = {
MyLogger() {
before = {
if (!sessions."${controllerName}") {
sessions."${controllerName}"="${controllerName}"
// now here you have a new user so set
// some session value for gsp or load something
//according
}else{
// user has hit it before do something else or set something else
}
}
}
}
}
and even simple than any of this would be to use the intelligence built into a gsp if what you load can be based on it... (not tested any of it ha)
<g:if test="${!session."${controllerName}"}">
<g:set var="${controllerName}" value="${controllerName}" scope="session" />
<g:render template="firstTimeHitter"/>
</g:if>
<g:else>
<g:render template="secondTimeHitter"/>
</g:else>
or just your controller that checks and sets that and either renders something different or sets something gsp picks up on..
def myController {
def doSomething() {
boolean firstTime = false
if (!session."${controllerName}") {
// first time either render or set firsTime
firstTime = true
session."${controllerName}" = controllerName // or startDate
// render view: 'firstTime, model: [firstTime:firstTime, params:params]
} else{
// render view: 'firstTime, model: [firstTime:firstTime, params:params]
}
// if no render above:
render view: 'doSomething, model: [firstTime:firstTime, params:params]
// now in doSomething gsp you look for firstTime:
}
do someThing:
<g:if test="${firstTime.toString().equals('true')}">
<g:render template="firstTimeHitter"/>
</g:if>
<g:else>
<g:render template="secondTimeHitter"/>
</g:else>
The possibilities are endless, the differences being with a filter its a one fits all, i.e. it is checking every controller as it is hit by each user. In controller and gsp solution you have to declare it where needed. You could have an abstract controller that other controllers extend to repeat that check as a higher class that gets called to verify, regardless their all a lot more repetitive than a simple one off filter...
Final Edit to give other other alternatives would be:
final Set<Session> jsessions = ([] as Set).asSynchronized()
jsessions.add('controller1')
jsessions.add('controller2')
jsessions.add('controller3')
jsessions.add(controllerName)
println "=== ${jsessions}"
if (jsessions.contains(controllerName)) {
println "--- We have ${controllerName} defined in our session set.... jsessions"
}
ArrayList jsessions2 = []
jsessions2.add(controllerName)
session.jsessions2 = jsessions2
//repeat this on every call
ArrayList jsessionsret = session.jsessions2
jsessionsret.add('controller1')
jsessionsret.add('controller2')
jsessionsret.add('controller3')
session.jsessions2 = jsessionsret
if (jsessions2.contains(controllerName)) {
println "--- We have ${controllerName} defined in our session set.... jsessionsret"
}
println "222 --- ${jsessions2}"
This segment above are two different implementations of using first a session set that is global and could be used if you do not care if the controller is hit by usera userb etc so if usera hits it userb would also be considered as hitting it.. This is jsessions.
The bottom jsessions2 is an attempt to turn a single session key into an ArrayList. So rather than storing lots of single object i.e. session."${controllerName}" per call of a controller per user session. You could have 1 single session key per user that you append each controller they hit to.. and you then check to see if they have that controller

How to add ajax to dynamically created primefaces input fields

I want to create a page to allow users to update a mysql table. This table can be changed by client admins so I have to read the table schema and create fields on the fly. I got the basic code for doing that from How to create dynamic JSF form fields and the ajax code from How to add ajax validation to programmatically generated primefaces component.
To create a proof of concept page I use the following code (note, I'm using primefaces):
for (int idx = 1; idx < 3; idx++) {
UIInput input = new InputText();
input.setId("text" + idx);
ValueExpression targetExpression = facesContext.getApplication().getExpressionFactory().createValueExpression(facesContext.getELContext(), "#{viewMakeFields.value}", String.class);
input.setValueExpression("value", targetExpression);
AjaxBehavior ab = new AjaxBehavior();
ab.setAsync(true);
ab.setProcess("text"+idx);
input.addClientBehavior("blur", ab); // "change" doesn't work either
form.getChildren().add(input);
}
Then, in the getter and setter, I'm getting the component ID to identify which field is changed:
public static String getCallingComponentID() {
UIComponent component = UIComponent.getCurrentComponent(FacesContext.getCurrentInstance());
return component.getId();
}
public String getValue() {
String id = getCallingComponentID();
System.out.println("getValue " + id);
return text1;
}
public void setValue(String text1) {
String id = getCallingComponentID();
System.out.println("setValue " + id);
this.text1 = text1;
}
The ajax isn't firing and when I click the submit button I get (and I know mixing partial and full submits isn't good):
INFO: getValue text1
INFO: getValue text2
INFO: getValue text1
INFO: getValue text2
INFO: setValue j_id1
INFO: setValue j_id1
INFO: getValue text1
INFO: getValue text2
I see two possible solutions: get ajax working so that the component calling the setter has the correct id or get the form submit to identify which child is calling the setter. The former is preferable since I want to disable the save button until something has changed but I'm willing to accept the latter at this point. Any help would be much appreciated.
Turns out this code does work. Somewhere in my meandering the error changed and I didn't understand the significance of that. Replacing head with h:head in the xhtml file that I was adding the fields to makes ajax work.

ASP.NET MVC3 using Redirect To Action

I want to use the Redirect to Action result on this code which gives a null but i have several if statements and the code is becoming more complex to build need a solution on how i could use the Redirect to Action which outputs null, help please?
public ActionResult Convert(double temperature, string convertTo)
{
ViewBag.Temperature = temperature;
ViewBag.ConvertTo = convertTo;
if (convertTo.Equals("Celsius"))
{ ViewBag.ConvertedTemperature = this.FahrenheitToCelsius(temperature); }
else
{ ViewBag.ConvertedTemperature = this.CelsiusToFahrenheit(temperature); }
return View("Convert");
}
The error message would really help. But it seems like you'd need to make your temperature parameter nullable, like so:
public ActionResult Convert(double? temperature, string convertTo)
Then you could check for null and return RedirectToAction:
if (temperature == null)
return RedirectToAction("ActionName", "ControllerName");
You'll also need to do the following to get the temperature value in your conversion methods:
temperature.Value
Hope this helps.

How to use Zend Framework Form Hash (token) with AJAX

I have included Zend_Form_Element_Hash into a form multiplecheckbox form. I have jQuery set to fire off an AJAX request when a checkbox is clicked, I pass the token with this AJAX request. The first AJAX request works great, but the subsequent ones fail.
I suspect it may be once the token has been validated it is then removed from the session (hop = 1).
What would be your plan of attack for securing a form with Zend Framework Hash yet using AJAX to complete some of these requests?
I finally abandoned using Zend_Form_Element_Hash and just created a token manually, registered it with Zend_Session and then checked it upon submission.
form.php
$myNamespace = new Zend_Session_Namespace('authtoken');
$myNamespace->setExpirationSeconds(900);
$myNamespace->authtoken = $hash = md5(uniqid(rand(),1));
$auth = new Zend_Form_Element_Hidden('authtoken');
$auth->setValue($hash)
->setRequired('true')
->removeDecorator('HtmlTag')
->removeDecorator('Label');
controller.php
$mysession = new Zend_Session_Namespace('authtoken');
$hash = $mysession->authtoken;
if($hash == $data['authtoken']){
print "success";
} else {
print "you fail";
}
This seems to work and still keeps things relatively sane and secure. I'd still rather use the Hash element, but I can't seem to make it work with AJAX.
Thanks all.
That's how to handled hash field in ajax form :
class AuthController extends Zend_Controller_Action
{
public function init()
{
$contextSwitch = $this->_helper->getHelper('contextSwitch');
$contextSwitch->addActionContext('index', 'json')
->initContext();
}
public function loginAction()
{
$form = new Application_Form_Login();
$request = $this->getRequest();
if ($request->isPost()) {
if ($form->isValid($request->getPost())) {
// some code ..
} else {
// some code ..
// Regenerate the hash and assign to the view
$reservationForm->hash->initCsrfToken();
$this->view->hash = $reservationForm->hash->getValue();
}
}
$this->view->form = $form;
}
}
And then in your view script ..
<? $this->dojo()->enable()
->requireModule('dojox.json.query')
->onLoadCaptureStart() ?>
function() {
var form = dojo.byId("login_form")
dojo.connect(form, "onsubmit", function(event) {
dojo.stopEvent(event);
var xhrArgs = {
form: this,
handleAs: "json",
load: function(data) {
// assign the new hash to the field
dojo.byId("hash").value = dojox.json.query("$.hash", data);
// some code ..
},
error: function(error) {
// some code ..
}
}
var deferred = dojo.xhrPost(xhrArgs);
});
}
<? $this->dojo()->onLoadCaptureEnd() ?>
Hope it's not too late :D
There is a solution:
Create, besides the form that will contain the data, a form without elements. From the controller you instantiate the two forms. Also in the controller, you add the element hash to the empty form. Both forms should be sent to the vision. Then, in the condition "if ($ request-> isXmlHttpRequest ())" in the controller you render the empty form. Then, you take the hash value with the method "getValue ()". This value must be sent in response by Ajax and then use JavaScript to replace the hash value that is already obsolete. The option to create an empty form for the hash is to avoid problems with other elements such as captcha that would have its id generated again if the form were rendered, and would also need to have the new information replaced. The validation will be done separately because there are two distinct forms. Later you can reuse the hash (empty) form whenever you want. The following are examples of the code.
//In the controller, after instantiating the empty form you add the Hash element to it:
$hash = new Zend_Form_Element_Hash('no_csrf_foo');
$hash_form->addElement('hash', 'no_csrf_foo', array('salt' => 'unique'));
//...
//Also in the controller, within the condition "if ($request->isXmlHttpRequest())" you render the form (this will renew the session for the next attempt to send the form) and get the new id value:
$hash_form->render($this->view);
$hash_value['hash'] = $hash_form->getElement('no_csrf_foo')->getValue();//The value must be added to the ajax response in JSON, for example. One can use the methods Zend_Json::decode($response) and Zend_Json::encode($array) for conversions between PHP array and JSON.
//---------------------------------------
//In JavaScript, the Ajax response function:
document.getElementById("no_csrf_foo").value = data.hash;//Retrieves the hash value from the Json response and set it to the hash input.
Leo
Form hashes are great in principle and a bit of a nightmare in practice. I think the best way to handle this is to return the new hash with the response when you make a request, and update the form markup or store in memory for your javascript as appropriate.
The new hash may be available from the form object, or you can read it from the session.
You hinted at the right answer in your question: increase the hop count.
There was specific mention of this in the ZF manual online, but they updated their manuals and now i can't find it (grin)- otherwise i would have posted the link for you.
If you want to use form validator in ajax side use following code :
Myform.php
class Application_Form_Myform extends Zend_Form
{
# init function & ...
public function generateform($nohash = false)
{
# Some elements
if(!$nohash)
{
$temp_csrf = new Zend_Session_Namespace('temp_csrf');
$my_hash = new Zend_Form_Element_Hash ( 'my_hash' );
$this->addElement ( $my_hash , 'my_hash');
$temp_csrf->hash = $my_hash->getHash();
}
# Some other elements
}
}
AjaxController.php
class AjaxController extends Zend_Controller_Action
{
// init ...
public function validateAction()
{
# ...
$temp_csrf = new Zend_Session_Namespace('temp_csrf');
if($temp_csrf->hash == $params['received_hash_from_client'])
{
$Myform = new Application_Form_Myform();
$Myform->generateform(true);
if($AF_Bill->isValid($params))
{
# Form data is valid
}else{
# Form invalid
}
}else{
# Received hash from client is not valid
}
# ...
}
}

Resources