I have below JSP page. Using this I can bind data and its working fine.
I am using logic:iterate for binding data from list.
What I am doing fetch the data from database and set it to list and using this list I can bind data into login iterate.
I am using below VO for bind data:
public class EDCPEmployeeRequestForm extends ActionForm {
private static final long serialVersionUID = 1L;
private String employeeCode ;
private String employeeName;
private String employeeAddress;
private String cardNo;
private String employeeEmailId;
private String employeeContactNo;
private String company;
private String strCompany;
private String employeeWorkCity;
private String employeeWorkLocation;
private String band;
private String status;
private EDCPNomineeDetailsForm[] nomineeDetailsList;
// getter and setter method....
.....
Now I want get the data from list which is use in the login:iterator. Why I need if any user login first time then empty list will generate and empty data all the field in which are used within login:iterate.
When user press the submit button in the the above form then below action class is execute :
public class EDCPEnrollmentAction extends Action {
Logger LOGGER = Logger.getLogger(this.getClass());
#Override
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpSession session = request.getSession(false);
EDCPEmployeeRequestForm eDCPEmployeeRequestForm = (EDCPEmployeeRequestForm) form;
LOGGER.info("EDCPRequest Object : "+eDCPEmployeeRequestForm.toString());
}
}
Ouput when user press submit button :
EDCPEmployeeRequestForm [employeeCode=123456, employeeName=Test,
employeeAddress=null, cardNo=null, employeeEmailId=test#gmail.com,
employeeContactNo=124589652, company=null, strCompany=1001,
employeeWorkCity=1001, employeeWorkLocation=10011, band=2D,
status=null, nomineeDetailsList=null]
You can see that nomineeDetailsList=null its showing null.
But now problem is that I am getting the value for nomineeDetailsList field. Every time I am getting null when I am trying to get value from VO.
My HTML file is designed as below :
<html:form action="/eDCPEnrollment" onsubmit="return checkallfields()">
<logic:iterate id="nomineeData" name="eDCPEmployeeRequestForm" property="nomineeDetailsList" indexId="index" >
<table width="709" border="0" align="center" cellpadding="1" cellspacing="0">
<tr>
<td width="162" height=10></td>
<td width="162"></td>
<td width="162"></td>
<td width="163"></td>
<td width="50"></td>
</tr>
<tr>
<td align="right" class="text">Name :</td>
<td align="center"><html:text property="firstName" name="nomineeData"
maxlength="25" styleClass="textfield" indexed="true"></html:text></td>
<td align="center"><html:text property="middleName" name="nomineeData"
maxlength="25" styleClass="textfield" indexed="true"></html:text></td>
<td align="center"><html:text property="lastName" name="nomineeData"
maxlength="25" styleClass="textfield" indexed="true"></html:text></td>
<td></td>
</tr>
<tr><td><html:submit styleClass="button"></html:submit></td></tr>
</table>
</html:form>
I am stuck here. Please correct me if I missing something.
Related
Hello Guys.
I have simple Storage page whichs display all Products from DB.
I set to each of them with Unique name to change the Amount of product.
When i want to catch this value in Java method its returns me null.
Can you help me what i need to do to corretly catching value's in this text inputs ?
Controller :
#Controller
public class StoragePageController extends HttpServlet {
#GET
#RequestMapping(value = "/storage/subamount/{id}")
public String substractTheAmountValue(#PathVariable("id") int id, Model model, HttpServletRequest request) {
String amount_req = request.getParameter("amount_sub_" + id);
System.out.println(amount_req);
return null;
}
}
JSP fragment :
<c:set var="licznik" value="${recordStartCounter }" />
<div align="center">
<table width="1000" border="0" cellpadding="6" cellspacing="2">
<c:forEach var="u" items="${productList }">
<c:set var="licznik" value="${licznik+1}" />
<tr onmouseover="changeTrBg(this)" onmouseout="defaultTrBg(this)">
<td align="right"><c:out value="${licznik }" /></td>
<td align="left"><c:out value="${u.description }" /></td>
<td align="left"><c:out value="${u.amount }" /></td>
<td align="center"><input type="text" name="amount_sub_${licznik}" id="amount_sub_${licznik}"></td>
<td align="center"><input type="button" value="Substract the value" onclick="window.location.href='${pageContext.request.contextPath}/storage/subamount/${licznik}'"/></td>
</tr>
</c:forEach>
</table>
You should be having your API controller like the one given below given that your UI is posting the data to your API / Controller (assuming you are using the latest version of Spring Boot). You have a #Get mapping which does not accept request payload in the body.
#RestController
public class StoragePageController {
#PostMapping(value = "/storage/subamount/{id}", produces = {"application/json"})
public String substractTheAmountValue(#PathVariable("id") int id, Model model) {
String amount_req = id;
System.out.println(amount_req);
return null;
}
}
I am having a lot of difficulty with POSTing back a form to the controller, which should contain simply an arraylist of objects that the user may edit.
The form loads up correctly, but when it's posted, it never seems to actually post anything.
Here is my form:
<form action="#" th:action="#{/query/submitQuery}" th:object="${clientList}" method="post">
<table class="table table-bordered table-hover table-striped">
<thead>
<tr>
<th>Select</th>
<th>Client ID</th>
<th>IP Addresss</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr th:each="currentClient, stat : ${clientList}">
<td><input type="checkbox" th:checked="${currentClient.selected}" /></td>
<td th:text="${currentClient.getClientID()}" ></td>
<td th:text="${currentClient.getIpAddress()}"></td>
<td th:text="${currentClient.getDescription()}" ></td>
</tr>
</tbody>
</table>
<button type="submit" value="submit" class="btn btn-success">Submit</button>
</form>
Above works fine, it loads up the list correctly. However, when I POST, it returns a empty object (of size 0). I believe this is due to the lack of th:field, but anyway here is controller POST method:
...
private List<ClientWithSelection> allClientsWithSelection = new ArrayList<ClientWithSelection>();
//GET method
...
model.addAttribute("clientList", allClientsWithSelection)
....
//POST method
#RequestMapping(value="/submitQuery", method = RequestMethod.POST)
public String processQuery(#ModelAttribute(value="clientList") ArrayList clientList, Model model){
//clientList== 0 in size
...
}
I have tried adding a th:field but regardless of what I do, it causes an exception.
I've tried:
...
<tr th:each="currentClient, stat : ${clientList}">
<td><input type="checkbox" th:checked="${currentClient.selected}" th:field="*{}" /></td>
<td th th:field="*{currentClient.selected}" ></td>
...
I cannot access currentClient (compile error), I can't even select clientList, it gives me options like get(), add(), clearAll() etc, so it things it should have an array, however, I cannot pass in an array.
I've also tried using something like th:field=${}, this causes runtime exception
I've tried
th:field = "*{clientList[__currentClient.clientID__]}"
but also compile error.
Any ideas?
UPDATE 1:
Tobias suggested that I need to wrap my list in a wraapper. So that's what I did:
ClientWithSelectionWrapper:
public class ClientWithSelectionListWrapper {
private ArrayList<ClientWithSelection> clientList;
public List<ClientWithSelection> getClientList(){
return clientList;
}
public void setClientList(ArrayList<ClientWithSelection> clients){
this.clientList = clients;
}
}
My page:
<form action="#" th:action="#{/query/submitQuery}" th:object="${wrapper}" method="post">
....
<tr th:each="currentClient, stat : ${wrapper.clientList}">
<td th:text="${stat}"></td>
<td>
<input type="checkbox"
th:name="|clientList[${stat.index}]|"
th:value="${currentClient.getClientID()}"
th:checked="${currentClient.selected}" />
</td>
<td th:text="${currentClient.getClientID()}" ></td>
<td th:text="${currentClient.getIpAddress()}"></td>
<td th:text="${currentClient.getDescription()}" ></td>
</tr>
Above loads fine:
Then my controller:
#RequestMapping(value="/submitQuery", method = RequestMethod.POST)
public String processQuery(#ModelAttribute ClientWithSelectionListWrapper wrapper, Model model){
...
}
The page loads correctly, the data is displayed as expected. If I post the form without any selection I get this:
org.springframework.expression.spel.SpelEvaluationException: EL1007E:(pos 0): Property or field 'clientList' cannot be found on null
Not sure why it's complaining
(In the GET Method it has: model.addAttribute("wrapper", wrapper);)
If I then make a selection, i.e. tick the first entry:
There was an unexpected error (type=Bad Request, status=400).
Validation failed for object='clientWithSelectionListWrapper'. Error count: 1
I'm guessing my POST controller is not getting the clientWithSelectionListWrapper. Not sure why, since I have set the wrapper object to be posted back via the th:object="wrapper" in the FORM header.
UPDATE 2:
I've made some progress! Finally the submitted form is being picked up by the POST method in controller. However, all the properties appear to be null, except for whether the item has been ticked or not. I've made various changes, this is how it is looking:
<form action="#" th:action="#{/query/submitQuery}" th:object="${wrapper}" method="post">
....
<tr th:each="currentClient, stat : ${clientList}">
<td th:text="${stat}"></td>
<td>
<input type="checkbox"
th:name="|clientList[${stat.index}]|"
th:value="${currentClient.getClientID()}"
th:checked="${currentClient.selected}"
th:field="*{clientList[__${stat.index}__].selected}">
</td>
<td th:text="${currentClient.getClientID()}"
th:field="*{clientList[__${stat.index}__].clientID}"
th:value="${currentClient.getClientID()}"
></td>
<td th:text="${currentClient.getIpAddress()}"
th:field="*{clientList[__${stat.index}__].ipAddress}"
th:value="${currentClient.getIpAddress()}"
></td>
<td th:text="${currentClient.getDescription()}"
th:field="*{clientList[__${stat.index}__].description}"
th:value="${currentClient.getDescription()}"
></td>
</tr>
I also added a default param-less constructor to my wrapper class and added a bindingResult param to POST method (not sure if needed).
public String processQuery(#ModelAttribute ClientWithSelectionListWrapper wrapper, BindingResult bindingResult, Model model)
So when an object is being posted, this is how it is looking:
Of course, the systemInfo is supposed to be null (at this stage), but the clientID is always 0, and ipAddress/Description always null. The selected boolean is correct though for all properties. I'm sure I've made a mistake on one of the properties somewhere. Back to investigation.
UPDATE 3:
Ok I've managed to fill up all the values correctly! But I had to change my td to include an <input /> which is not what I wanted... Nonetheless, the values are populating correctly, suggesting spring looks for an input tag perhaps for data mapping?
Here is an example of how I changed the clientID table data:
<td>
<input type="text" readonly="readonly"
th:name="|clientList[${stat.index}]|"
th:value="${currentClient.getClientID()}"
th:field="*{clientList[__${stat.index}__].clientID}"
/>
</td>
Now I need to figure out how to display it as plain data, ideally without any presence of an input box...
You need a wrapper object to hold the submited data, like this one:
public class ClientForm {
private ArrayList<String> clientList;
public ArrayList<String> getClientList() {
return clientList;
}
public void setClientList(ArrayList<String> clientList) {
this.clientList = clientList;
}
}
and use it as the #ModelAttribute in your processQuery method:
#RequestMapping(value="/submitQuery", method = RequestMethod.POST)
public String processQuery(#ModelAttribute ClientForm form, Model model){
System.out.println(form.getClientList());
}
Moreover, the input element needs a name and a value. If you directly build the html, then take into account that the name must be clientList[i], where i is the position of the item in the list:
<tr th:each="currentClient, stat : ${clientList}">
<td><input type="checkbox"
th:name="|clientList[${stat.index}]|"
th:value="${currentClient.getClientID()}"
th:checked="${currentClient.selected}" />
</td>
<td th:text="${currentClient.getClientID()}" ></td>
<td th:text="${currentClient.getIpAddress()}"></td>
<td th:text="${currentClient.getDescription()}" ></td>
</tr>
Note that clientList can contain null at
intermediate positions. Per example, if posted data is:
clientList[1] = 'B'
clientList[3] = 'D'
the resulting ArrayList will be: [null, B, null, D]
UPDATE 1:
In my exmple above, ClientForm is a wrapper for List<String>. But in your case ClientWithSelectionListWrapper contains ArrayList<ClientWithSelection>. Therefor clientList[1] should be clientList[1].clientID and so on with the other properties you want to sent back:
<tr th:each="currentClient, stat : ${wrapper.clientList}">
<td><input type="checkbox" th:name="|clientList[${stat.index}].clientID|"
th:value="${currentClient.getClientID()}" th:checked="${currentClient.selected}" /></td>
<td th:text="${currentClient.getClientID()}"></td>
<td th:text="${currentClient.getIpAddress()}"></td>
<td th:text="${currentClient.getDescription()}"></td>
</tr>
I've built a little demo, so you can test it:
Application.java
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
ClientWithSelection.java
public class ClientWithSelection {
private Boolean selected;
private String clientID;
private String ipAddress;
private String description;
public ClientWithSelection() {
}
public ClientWithSelection(Boolean selected, String clientID, String ipAddress, String description) {
super();
this.selected = selected;
this.clientID = clientID;
this.ipAddress = ipAddress;
this.description = description;
}
/* Getters and setters ... */
}
ClientWithSelectionListWrapper.java
public class ClientWithSelectionListWrapper {
private ArrayList<ClientWithSelection> clientList;
public ArrayList<ClientWithSelection> getClientList() {
return clientList;
}
public void setClientList(ArrayList<ClientWithSelection> clients) {
this.clientList = clients;
}
}
TestController.java
#Controller
class TestController {
private ArrayList<ClientWithSelection> allClientsWithSelection = new ArrayList<ClientWithSelection>();
public TestController() {
/* Dummy data */
allClientsWithSelection.add(new ClientWithSelection(false, "1", "192.168.0.10", "Client A"));
allClientsWithSelection.add(new ClientWithSelection(false, "2", "192.168.0.11", "Client B"));
allClientsWithSelection.add(new ClientWithSelection(false, "3", "192.168.0.12", "Client C"));
allClientsWithSelection.add(new ClientWithSelection(false, "4", "192.168.0.13", "Client D"));
}
#RequestMapping("/")
String index(Model model) {
ClientWithSelectionListWrapper wrapper = new ClientWithSelectionListWrapper();
wrapper.setClientList(allClientsWithSelection);
model.addAttribute("wrapper", wrapper);
return "test";
}
#RequestMapping(value = "/query/submitQuery", method = RequestMethod.POST)
public String processQuery(#ModelAttribute ClientWithSelectionListWrapper wrapper, Model model) {
System.out.println(wrapper.getClientList() != null ? wrapper.getClientList().size() : "null list");
System.out.println("--");
model.addAttribute("wrapper", wrapper);
return "test";
}
}
test.html
<!DOCTYPE html>
<html>
<head></head>
<body>
<form action="#" th:action="#{/query/submitQuery}" th:object="${wrapper}" method="post">
<table class="table table-bordered table-hover table-striped">
<thead>
<tr>
<th>Select</th>
<th>Client ID</th>
<th>IP Addresss</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr th:each="currentClient, stat : ${wrapper.clientList}">
<td><input type="checkbox" th:name="|clientList[${stat.index}].clientID|"
th:value="${currentClient.getClientID()}" th:checked="${currentClient.selected}" /></td>
<td th:text="${currentClient.getClientID()}"></td>
<td th:text="${currentClient.getIpAddress()}"></td>
<td th:text="${currentClient.getDescription()}"></td>
</tr>
</tbody>
</table>
<button type="submit" value="submit" class="btn btn-success">Submit</button>
</form>
</body>
</html>
UPDATE 1.B:
Below is the same example using th:field and sending back all other attributes as hidden values.
<tbody>
<tr th:each="currentClient, stat : *{clientList}">
<td>
<input type="checkbox" th:field="*{clientList[__${stat.index}__].selected}" />
<input type="hidden" th:field="*{clientList[__${stat.index}__].clientID}" />
<input type="hidden" th:field="*{clientList[__${stat.index}__].ipAddress}" />
<input type="hidden" th:field="*{clientList[__${stat.index}__].description}" />
</td>
<td th:text="${currentClient.getClientID()}"></td>
<td th:text="${currentClient.getIpAddress()}"></td>
<td th:text="${currentClient.getDescription()}"></td>
</tr>
</tbody>
When you want to select objects in thymeleaf, you dont actually need to create a wrapper for the purpose of storing a boolean select field. Using dynamic fields as per the thymeleaf guide with syntax th:field="*{rows[__${rowStat.index}__].variety}" is good for when you want to access an already existing set of objects in a collection. Its not really designed for doing selections by using wrapper objects IMO as it creates unnecessary boilerplate code and is sort of a hack.
Consider this simple example, a Person can select Drinks they like. Note: Constructors, Getters and setters are omitted for clarity. Also, these objects are normally stored in a database but I am using in memory arrays to explain the concept.
public class Person {
private Long id;
private List<Drink> drinks;
}
public class Drink {
private Long id;
private String name;
}
Spring controllers
The main thing here is that we are storing the Person in the Model so we can bind it to the form within th:object.
Secondly, the selectableDrinks are the drinks a person can select on the UI.
#GetMapping("/drinks")
public String getDrinks(Model model) {
Person person = new Person(30L);
// ud normally get these from the database.
List<Drink> selectableDrinks = Arrays.asList(
new Drink(1L, "coke"),
new Drink(2L, "fanta"),
new Drink(3L, "sprite")
);
model.addAttribute("person", person);
model.addAttribute("selectableDrinks", selectableDrinks);
return "templates/drinks";
}
#PostMapping("/drinks")
public String postDrinks(#ModelAttribute("person") Person person) {
// person.drinks will contain only the selected drinks
System.out.println(person);
return "templates/drinks";
}
Template code
Pay close attention to the li loop and how selectableDrinks is used to get all possible drinks that can be selected.
The checkbox th:field really expands to person.drinks since th:object is bound to Person and *{drinks} simply is the shortcut to referring to a property on the Person object. You can think of this as just telling spring/thymeleaf that any selected Drinks are going to be put into the ArrayList at location person.drinks.
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" >
<body>
<div class="ui top attached segment">
<div class="ui top attached label">Drink demo</div>
<form class="ui form" th:action="#{/drinks}" method="post" th:object="${person}">
<ul>
<li th:each="drink : ${selectableDrinks}">
<div class="ui checkbox">
<input type="checkbox" th:field="*{drinks}" th:value="${drink.id}">
<label th:text="${drink.name}"></label>
</div>
</li>
</ul>
<div class="field">
<button class="ui button" type="submit">Submit</button>
</div>
</form>
</div>
</body>
</html>
Any way...the secret sauce is using th:value=${drinks.id}. This relies on spring converters. When the form is posted, spring will try recreate a Person and to do this it needs to know how to convert any selected drink.id strings into the actual Drink type. Note: If you did th:value${drinks} the value key in the checkbox html would be the toString() representation of a Drink which is not what you want, hence need to use the id!. If you are following along, all you need to do is create your own converter if one isn't already created.
Without a converter you will receive an error like
Failed to convert property value of type 'java.lang.String' to required type 'java.util.List' for property 'drinks'
You can turn on logging in application.properties to see the errors in detail.
logging.level.org.springframework.web=TRACE
This just means spring doesn't know how to convert a string id representing a drink.id into a Drink. The below is an example of a Converter that fixes this issue. Normally you would inject a repository in get access the database.
#Component
public class DrinkConverter implements Converter<String, Drink> {
#Override
public Drink convert(String id) {
System.out.println("Trying to convert id=" + id + " into a drink");
int parsedId = Integer.parseInt(id);
List<Drink> selectableDrinks = Arrays.asList(
new Drink(1L, "coke"),
new Drink(2L, "fanta"),
new Drink(3L, "sprite")
);
int index = parsedId - 1;
return selectableDrinks.get(index);
}
}
If an entity has a corresponding spring data repository, spring automatically creates the converters and will handle fetching the entity when an id is provided (string id seems to be fine too so spring does some additional conversions there by the looks). This is really cool but can be confusing to understand at first.
1st problem : i have a jsp in which there are two tabs ,for the second tab i have included the struts include tag. When i open the second tab and performs the action the second tab form values are not passing to the action.
2nd problem : in the select tag i have populate the list but it is coming as prepopulated means all the options are coming as selected="selected"
main jsp in which tabs are made
<!-- admin first tab starts here -->
<form action="saveRolesAndPermissions" method="post">
<table align="center">
<tr>
<td ><s:text name="FTID" ></s:text></td>
<td ><s:textfield id="FTID" name="ft_id">
</s:textfield></td>
<td><input type="button" value="validate" onclick="userPresent()"></td>
</tr>
</table>
<table>
<tr>
<td>First Name</td>
<td><input id="first_name" type="text" readonly onkeydown="return false"></td>
<td>Last Name</td>
<td><input id="last_name"
type="text" readonly onkeydown="return false"></td>
<td>Email-Id</td>
<td><input id="mail_id" type="text"
readonly onkeydown="return false"></td>
</tr>
</table>
<table align="center">
<tr>
<td><s:text name="ROLES"></s:text></td>
<td></td>
<td></td>
</tr>
<tr>
<td><s:text name="Available Roles"></s:text></td>
<td></td>
<td><s:text name="Assigned Roles"></s:text></td>
</tr>
<tr>
<td><s:select id="roles" name="availableRole"
multiple="true" list="availableRole"></s:select></td>
<td><input type="button" value=">" onclick="move_list_items('roles','assignedroles');"/><input
type="button" value="<" onclick="move_list_items('assignedroles','roles');"/></td>
<td><s:select id="assignedroles" name="assignedRole" multiple="true"
list="{}" >
</s:select></td>
</tr>
</table>
<br /> <br /> <br />
<table>
<tr>
<td><s:text name="Permissions"></s:text></td>
<td></td>
<td> </td>
</tr>
<tr>
<td><s:text
name="Available Permissions"></s:text></td>
<td></td>
<td><s:text name="Assigned Permissions"></s:text></td>
</tr>
<tr>
<td><s:select id="permissions" multiple="true"
name="availablePermission" list="availablePermission" headerValue=""></s:select></td>
<td><input
type="button" value=">" onclick="move_list_items('permissions','assignedpermissions');"/><br /> <input type="button"
value="<" onclick="move_list_items('assignedpermissions','permissions');" /></td>
<td><s:select id="assignedpermissions" multiple="true" name="assignedPermission"
list="{}" ></s:select></td>
</tr>
</table>
<br /> <br />
<table align="center" style="width: 25%;">
<tr>
<td><s:if test="hasActionMessages()">
<div class="welcome" style="list-style:none">
<s:actionmessage />
</div>
</s:if></td>
</tr>
</table>
<table>
<tr>
<td><s:submit
value="save"onclick="saveRole();return false;"></s:submit></td>
<td> <input type="button" name="close"
value="close" /></td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
</table>
</form>
<!-- second tab for modify roles -->
<div id="content02" class="content" >
<s:include value="../asp/aspAdminModify.jsp"></s:include>
</div>
<!-- /second tab ends here -->
included jsp
<form action="grantedRolesAndPermissions" method="post">
<table>
<tr>
<td><s:text name="FTID" ></s:text></td>
<td><s:textfield id="modify_FTID" name="modifyftid">
</s:textfield></td>
<td><s:submit
value="search" onclick="search();return false;"></s:submit>
</td>
</tr>
</table>
Bean for the first tab
private String ft_id;
private ArrayList<String> availableRole;
private ArrayList<String> availablePermission;
private ArrayList<String> assignedRole;
private ArrayList<String> assignedPermission;
//getters and setters
Action for the first tab
public class ASPadmin extends ActionSupport implements ServletRequestAware, ModelDriven<ASPAdminBean>{
/**
*
*/
private static final long serialVersionUID = 1L;
private AdminASPService aspService = new AdminASPService();
private HttpServletRequest request = ServletActionContext.getRequest();
private HttpServletResponse response = ServletActionContext.getResponse();
public CMTUser cmtuser;
private ASPAdminBean aspAdminBean = new ASPAdminBean();
//getters and setters
public String populateRolesAndPermissions() throws Exception
{
/*aspAdminBean=new ASPAdminBean();*/
aspAdminBean.setAvailableRole(aspService.getRolesList());
aspAdminBean.setAvailablePermission(aspService.getPermissionsList());
return SUCCESS;
}
public String saveRolesAndPermissions() throws Exception
{
User user = CMTUser.getUser(request);
String login = user.getUserId();
String[] temp = login.split("\\.");
String abcfinal = temp[0].substring(0, 1).toUpperCase()
+ temp[0].substring(1);
String deffinal = temp[1].substring(0, 1).toUpperCase()
+ temp[1].substring(1);
String name = abcfinal + " " + deffinal;
System.out.println("name ==============>" + name);
String id = aspService.saveRolesPermissions(aspAdminBean,name);
System.out.println("id=======>"+id);
if("Y".equals(id)){
addActionMessage("Record Inserted Successfully");
populateRolesAndPermissions();
return SUCCESS;
}
else{
return ERROR;
}
}
#Override
public String execute() throws Exception {
String url = request.getRequestURL().toString();
String[] actionArray = url.split("/");
String event = null;
String forward = SUCCESS;
for (int i = 0; i < actionArray.length; i++) {
event = actionArray[i];
}
System.err.println(event);
try {
if (event.equals("aspAdmin.action")) {
populateRolesAndPermissions();
}
}catch (Exception e) {
e.printStackTrace();
}
return SUCCESS;
}
#Override
public void setServletRequest(HttpServletRequest req) {
this.request = req;
}
#Override
public ASPAdminBean getModel() {
// TODO Auto-generated method stub
return aspAdminBean;
}
}
bean for second tab
public class ASPAdminModifyBean {
private String modifyftid;
private String aspmodifyassignedRole;
private String aspmodifyassignedPermission;
private String createddate;
private String createdby;
private String updateddate;
private String updatedby;
private String username;
private ArrayList<String> modifyavailableRole;
private ArrayList<String> modifyavailablePermission;
private ArrayList<String> modifyassignedRole;
private ArrayList<String> modifyassignedPermission;
//getters and setters
action for the second tab
public class ASPadminModify extends ActionSupport implements ServletRequestAware, ModelDriven<ASPAdminModifyBean> {
private AdminASPService aspService = new AdminASPService();
private GetRolePermissionListInt[] roleVO;
private HttpServletRequest request = ServletActionContext.getRequest();
private HttpServletResponse response = ServletActionContext.getResponse();
private ASPAdminModifyBean modify = new ASPAdminModifyBean();
GetRolePermissionListInt role;
//getters and setters for the above
public String grantRolesPermissions(){
System.out.println("enter the grant roles and permissions");
String tab2="modify";
boolean id;
HttpServletRequest request=getRequest();
HttpSession session=request.getSession();
session.setAttribute("tabs",tab2 );
role=aspService.getGrantedRolesAndPermissions(modify);
System.out.println("assigned roles===================>"+role.getAssignedRoles());
modify.setAspmodifyassignedRole(role.getAssignedRoles());
modify.setAspmodifyassignedPermission(role.getAssignedPermissions());
modify.setCreatedby(role.getCreatedBy());
modify.setCreateddate(role.getCreatedDate());
modify.setUpdatedby(role.getUpdatedBy());
modify.setUpdateddate(role.getUpdatedDate());
modify.setUsername(role.getUserName());
modify.setModifyftid(role.getFtid());
System.out.println("assigned permissions==============>"+role.getAssignedPermissions());
System.out.println("updated by=================>"+role.getUpdatedBy());
System.out.println("update date=================>"+role.getUpdatedDate());
System.out.println("created by===================>"+role.getCreatedBy());
System.out.println("created date=====================>"+role.getCreatedDate());
System.out.println("ftid=============================>"+role.getFtid());
System.out.println("user name===========================>"+role.getUserName());
System.out.println("ftid=============>"+role.getFtid());
if(role!=null){
return SUCCESS;
}else{
return ERROR;
}
}
#Override
public void setServletRequest(HttpServletRequest arg0) {
// TODO Auto-generated method stub
}
#Override
public ASPAdminModifyBean getModel() {
// TODO Auto-generated method stub
return modify;
}
}
Well, the code is grown again :)
Start by :
changing your ArrayList declarations to List (in both beans, and regenerate getters and setters);
changing the way you get the Request, the Response and the Session, by using Struts2 Aware s interfaces (and their setters, with code inside)
Then if it still doesn't work, describe a little better what do you mean by "values are not passing to Action", and consider posting your interceptor stack config.
Hope that helps...
I'm using spring mvc for the first time and I'm trying to display and edit a structure in jsp.
I have a class Snippet, which holds a list of objects of type Sentence:
public class Snippet {
private int id;
private List<Sentence> sentences;
// getters, setters, default constructor
}
public class Sentence {
private int id;
private int scale;
private String text;
// getters, setters, default constructor
}
In my controller I give a new snippet for editing and when user clicks "save" store it to my db, then return another one. Currently the sentences list of the snippet is null:
#RequestMapping("/snippet")
public ModelAndView getSnippet() {
return new ModelAndView("snippet", "snippet", snippetService.getSnippet());
}
#RequestMapping("/save")
public ModelAndView saveSnippet(#ModelAttribute Snippet snippet) {
if(snippet != null && snippet.getSentences() != null && !snippet.getSentences().isEmpty()) {
snippetService.updateSnippet(snippet);
}
return new ModelAndView("snippet", "snippet", snippetService.getSnippet());
}
In my snippet.jsp I'd like to display the snippet sentences with their scale, and on save, pass snippet with sentences and scales to the controller for storage:
<form:form method="post" action="save" modelAttribute="snippet">
...
<c:forEach var="sentence" items="${snippet.sentences}">
<tr>
<td>${sentence.id}</td>
<td>${sentence.text}</td>
<td><input type="range" name="sentence.scale" value="${sentence.scale}"
path="sentence.scale" min="0" max="5" /></td>
</tr>
</c:forEach>
<tr>
<td colspan="4"><input type="submit" value="Save" /></td>
</tr>
I think I have to find the right way to use the path attribute but I can't figure it out.
The JSTL c:forEach tag provides the attribute varStatus, which will expose the loop status to the specified variable. Reference the index of varStatus to obtain the index of the current loop and use that index to specify the index of the collection item you want to bind or display.
<c:forEach var="sentence" items="${snippet.sentences}" varStatus="i">
<tr>
<td>${sentence.id}</td>
<td>${sentence.text}</td>
<td>
<form:input type="range"
name="snippet.sentences[${i.index}].scale"
path="sentences[${i.index}].scale"
min="0" max="5"
/></td>
</tr>
</c:forEach>
For example, there is an action class as follows.
#Namespace("/admin_side")
#ResultPath("/WEB-INF/content")
#InterceptorRefs({#InterceptorRef(value="defaultStack", params={"validation.excludeMethods", "load"})})
public final class TestAction extends ActionSupport implements Serializable, ValidationAware, ModelDriven<Transporter>
{
#Autowired
private final transient TransporterService transporterService=null;
private static final long serialVersionUID = 1L;
private Boolean deleteOneRow=false; //Getter and setter.
private Transporter entity=new Transporter(); //Getter and setter.
private List<Transporter>transporters=new ArrayList<Transporter>();
private String message; //Getter and setter.
private List<Long>chk; //Getter and setter.
#Action(value = "Transporter", results = {#Result(name=ActionSupport.SUCCESS, location="Transporter.jsp"), #Result(name = ActionSupport.INPUT, location = "Transporter.jsp")})
public String load() throws Exception
{
return ActionSupport.SUCCESS;
}
#Validations(
requiredStrings={
#RequiredStringValidator(fieldName="transporterName", type= ValidatorType.FIELD, key = "transporter.name.required"),
#RequiredStringValidator(fieldName="transporterWebsite", type= ValidatorType.FIELD, key = "transporter.website.required")},
stringLengthFields={
#StringLengthFieldValidator(fieldName="transporterName", type= ValidatorType.FIELD, minLength="2", maxLength="45", key="transporter.name.length", messageParams={"2", "45"}),
#StringLengthFieldValidator(fieldName="transporterWebsite", type= ValidatorType.FIELD, minLength="10", maxLength="1000", key="transporter.website.length", messageParams={"10", "1000"})})
#Action(value = "addTransporter",
results = {#Result(name=ActionSupport.SUCCESS, type="redirectAction", location="Transporter.jsp", params={"namespace", "/admin_side", "actionName", "Transporter", "message", "${message}"}),
#Result(name = ActionSupport.INPUT, location = "Transporter.jsp")},
interceptorRefs={#InterceptorRef(value="defaultStack", params={"params.acceptParamNames", "transporterName, transporterWebsite", "validation.validateAnnotatedMethodOnly", "true"})})
public String insert()
{
if(entity.getTransporterId()==null)
{
transporterService.insert(entity.getTransporterName(), entity.getTransporterWebsite());
setMessage(getText("insert.success"));
}
else
{
setMessage(transporterService.update(entity)?getText("update.success", new String[]{String.valueOf(entity.getTransporterId())}) :getText("update.failed", new String[]{String.valueOf(entity.getTransporterId())}));
}
return ActionSupport.SUCCESS;
}
#Validations(requiredFields={#RequiredFieldValidator(fieldName="transporterId", type= ValidatorType.FIELD, key = "delete.id.missing")})
#Action(value = "editTransporter",
results = {
#Result(name=ActionSupport.SUCCESS, location="Transporter.jsp"),
#Result(name = ActionSupport.INPUT, location = "Transporter.jsp")},
interceptorRefs={
#InterceptorRef(value="defaultStack", params={"params.acceptParamNames", "transporterId, transporterName, transporterWebsite", "validation.validateAnnotatedMethodOnly", "true"}),
#InterceptorRef(value="conversionError")})
public String edit()
{
return ActionSupport.SUCCESS;
}
#Action(value = "deleteTransporter",
results = {
#Result(name=ActionSupport.SUCCESS, type="redirectAction", location="Transporter.action", params={"message", "${message}"}),
#Result(name = ActionSupport.INPUT, location = "Transporter.jsp")},
interceptorRefs={
#InterceptorRef(value="defaultStack", params={"params.acceptParamNames", "transporterId, deleteOneRow", "validation.validateAnnotatedMethodOnly", "true"}),
#InterceptorRef(value="conversionError")})
public String deleteTransporter()
{
if(transporterService.delete(entity.getTransporterId()))
{
//Pagination has not not yet been implemented. Hence, it is static.
transporters=transporterService.getList(0, 20);
setMessage(getText("delete.success", new String[]{String.valueOf(entity.getTransporterId())}));
}
else
{
setMessage(getText("delete.failed", new String[]{String.valueOf(entity.getTransporterId())}));
}
return ActionSupport.SUCCESS;
}
#Action(value = "deleteTransporters",
results = {
#Result(name=ActionSupport.SUCCESS, type="redirectAction", location="Transporter.jsp", params={"namespace", "/admin_side", "actionName", "Transporter", "message", "${message}"}),
#Result(name = ActionSupport.INPUT, location = "Transporter.jsp")},
interceptorRefs={
#InterceptorRef(value="defaultStack", params={"params.acceptParamNames", "chk", "validation.validateAnnotatedMethodOnly", "true"}),
#InterceptorRef(value="conversionError")})
public String deleteTransporters()
{
setMessage(transporterService.delete(chk)?getText("delete.multiple.success", new String[]{String.valueOf(chk.size())}) :getText("delete.multiple.failed"));
return ActionSupport.SUCCESS;
}
#Override
public Transporter getModel() {
return entity;
}
public List<Transporter> getTransporters()
{
if(CollectionUtils.isEmpty(transporters))
{
//Pagination has not not yet been implemented. Hence, it is static.
transporters=transporterService.getList(0, 20);
}
return transporters;
}
public void setTransporters(List<Transporter> transporters) {
this.transporters = transporters;
}
#Override
public void validate(){}
}
The JSP page:
<s:form namespace="/admin_side" action="Transporter" id="dataForm" name="dataForm" cssClass="search_form general_form">
<s:if test="hasFieldErrors()">
<s:fielderror fieldName="transporterId"/>
<s:fielderror fieldName="chk"/>
</s:if>
<s:property value="message"/>
<s:hidden id="transporterId" name="transporterId"/>
<s:hidden id="deleteOneRow" name="deleteOneRow"/>
<s:textfield id="transporterName" name="transporterName"/><s:fielderror fieldName="transporterName"/>
<s:textfield id="transporterWebsite" name="transporterWebsite"/><s:fielderror fieldName="transporterWebsite"/>
<s:submit id="btnSubmit" name="btnSubmit" value="Submit" action="addTransporter"/>
<table cellpadding="0" cellspacing="0" width="100%">
<tbody>
<tr class="even">
<th style="width: 96px;">Check</th>
<th style="width: 96px;">Id</th>
<th style="width: 96px;">Transporter</th>
<th style="width: 96px;">Website</th>
<th style="width: 96px;">Actions</th>
</tr>
<s:iterator value="transporters" status="loopStatus">
<tr class="<s:if test="#loopStatus.odd == true ">first</s:if> <s:else>second</s:else>">
<td><s:checkbox name="chk" fieldValue="%{transporterId}" value="false"/></td>
<td><s:property value="transporterId" /></td>
<td><s:property value="transporterName" /></td>
<td>
Visit
</td>
<td>
<div class='actions'>
<ul>
<li>
<s:url id="editURL" action="editTransporter" escapeAmp="false">
<s:param name="transporterId" value="%{transporterId}"/>
<s:param name="transporterName" value="%{transporterName}"/>
<s:param name="transporterWebsite" value="%{transporterWebsite}"/>
</s:url>
<s:a href="%{editURL}" cssClass="action2"/>
</li>
<li>
<s:url id="deleteURL" action="deleteTransporter" escapeAmp="false">
<s:param name="transporterId" value="%{transporterId}"/>
<s:param name="deleteOneRow" value="%{deleteOneRow}"/>
</s:url>
<s:a href="%{deleteURL}" onclick="return deleteOne(%{transporterId});" cssClass="action4"/>
</li>
</ul>
</div>
</td>
</tr>
</s:iterator>
</tbody>
</table>
<s:submit name="btnDelete" id="btnDelete" action="deleteTransporters" onclick="return getCheckedRows();" />
The insert() method accepts two parameters, transporterName and transporterWebsite and the edit() method accepts only one parameter transporterId which is supplied as a query-string, when a link is clicked.
The insert() method is mapped by an action of <s:submit> whereas the edit() method is mapped by an action of <s:url> whose id is given to the href attribute of <s:a>.
When the edit link, <s:a> is clicked, both the text fields transporterName and transporterWebsite are unnecessarily validated which must not happen while editing i.e validation to these text fields should be skipped/disabled, when the edit link is clicked.
Only transporterId which is accepted by the edit() method should be validated. No other fields should be validated, when the edit link is clicked.
The annotation #SkipValidation would not work, in this case.
How to do this?
It was because I was missing validateAnnotatedMethodOnly at the class level validation interceptor I defined.
It worked when I modified the class definition to something like the following.
#Namespace("/admin_side")
#ResultPath("/WEB-INF/content")
#InterceptorRefs({#InterceptorRef(value="defaultStack", params={"validation.validateAnnotatedMethodOnly", "true", "validation.excludeMethods", "load"})})
public final class TestAction extends ActionSupport implements Serializable, ValidationAware, ModelDriven<Transporter>
{
//...
}
I included validation.validateAnnotatedMethodOnly at method levels but forgot to include it at the class level.
It would have also been appropriate to just annotate the load() method in the action class with #SkipValidation and eliminate the class level #InterceptorRefs annotation in its entirely.
From the documentation:
When multiple methods are used to map different actions on the same
class, and one of them is annotated with #Validations, those
validators will be triggered for all the actions, unless they are
annotated with #SkipValidation or validateAnnotatedMethodOnly is set
to true in the validation interceptor, like:
<interceptor-ref name="validation">
<param name="validateAnnotatedMethodOnly">true</param>
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>