I have been trying to display a table in JSP for which I am using this while loop code as given below, the problem is that it is difficult for me to convert my scriptlets into JSTL especially the rs.getInt("id") and I am using JSTL so that I can encode the URL together.
Class.forName("com.mysql.cj.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/login";
String username = "root";
String password = "your-password";
String query = "select * from employeesloginaccount";
Connection conn = DriverManager.getConnection(url, username, password);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
%>
<tr>
<td><%=rs.getInt("id")%></td>
<td><%=rs.getString("first_name")%></td>
<td><%=rs.getString("last_name")%></td>
<td>
<c:url value ="${pageContext.request.contextPath}/downloadFileServlet" var = "myURL">
<c:param name = "id" value = "<%=rs.getInt(id)%>"/>
</c:url>
<form method="get"
action="<c:import url = "${myURL}"/>">
<input style="text-align: center" type="submit" value="Save">
</form>
</td>
</tr>
<%
}
I think it might be worth considering this answer from BalusC on the question, "How to avoid Java code in JSP files?"
The use of scriptlets (those <% %> things) in JSP is indeed
highly discouraged since the birth of taglibs (like JSTL) and
EL (Expression Language, those ${} things) over a decade ago.
The major disadvantages of scriptlets are:
Reusability: you can't reuse scriptlets.
Replaceability: you can't make scriptlets abstract.
OO-ability: you can't make use of inheritance/composition.
Debuggability: if scriptlet throws an exception halfway, all you get is a blank page.
Testability: scriptlets are not unit-testable.
Maintainability: per saldo more time is needed to maintain mingled/cluttered/duplicated code logic.
Your specific problem here is Maintainability.
What you should be doing is seperating the logic of your application so that you can have a high level of reusability/testability/debuggability/maintainability etc.. Let's start by creating a java class for your database connection, maybe something like this:
public class DBConnection {
private static String url = null;
private static Connection conn = null;
public static Connection getConnection(){
try{
Class.forName("com.mysql.jdbc.Driver");
url = "jdbc:mysql://localhost:3306/login";
conn = DriverManager.getConnection(url,"root","your-password");
} catch (Exception e) {
System.out.println(e);
}
return conn;
}
}
Then you can use this class whenever you want to connect to your database and do something from other classes, in the examples below we will create an object to handle your employee data and then use that to get information from your database:
public class EmployeeObject {
int id;
String firstname;
String lastname;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
}
Now that we have this object class, let's say you have another class called Employees, and in this class you have a method which gets employee info from the employeesloginaccount table:
public class Employees {
public List<EmployeeObject> getEmployeeInfo(){
//this class will return a list of EmployeeObjects from the database.
ArrayList<EmployeeObject> employees = new ArrayList<EmployeeObject>();
//get connection from our DBConneciton class we created earlier
try(Connection conn= DBConnection.getConnection()){
PreparedStatement pst = conn.prepareStatement("select * from employeesloginaccount;");
ResultSet rs = pst.executeQuery();
while (rs.next()) {
//for each result in database, create an EmployeeObject
EmployeeObject employee = new EmployeeObject();
int id = rs.getInt("id");
employee.setId(id);
String fname = rs.getString("first_name");
employee.setFirstname(fname);
String lname = rs.getString("last_name");
employee.setLastname(lname);
employees.add(employee); // add each EmployeeObject to the arrayList of EmployeeObject's
}
} catch (SQLException e) {
e.printStackTrace();
}
return employees; //return all the results
}
}
Then you create a Servlet which will get this information, let's make it easy and put our code in the doGet method of the servlet so that whenever we visit the URL for this Servlet we will call this code (in this case i called my Servlet Test, with url mapping /Test:
#WebServlet("/Test")
public class Test extends HttpServlet {
private static final long serialVersionUID = 1L;
public Test() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Employees e = new Employees(); //instantiate the Employees class
List<EmployeeObject> employees = e.getEmployeeInfo(); //get employee info from database
request.setAttribute("employees", employees); //set this list of employees to the request so we can access it in our jsp
RequestDispatcher rd = request.getRequestDispatcher("example.jsp"); //change to whatever your jsp is that you want to view the information
rd.forward(request, response);
}
}
And finally in our jsp page where we can view this information:
<!DOCTYPE HTML>
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%# taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<%# page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<html>
<head>
<title>Example Page</title>
</head>
<body>
<table style="width:100%;">
<thead>
<tr>
<td>id</td>
<td>Firstname</td>
<td>Lastname</td>
</tr>
</thead>
<tbody>
<!-- for each item in our employees list create a variable called "employee" -->
<c:forEach items="${employees}" var="employee">
<tr>
<td>${employee.id}</td>
<td>${employee.firstname}</td>
<td>${employee.lastname}</td>
</tr>
</c:forEach>
</tbody>
</table>
</body>
</html>
Let me know if that helps you or if you have any questions. :)
Related
I have a table FAQ ( Frequently asked questions )
Here's the Bean:
package projet.helpdesk.beans;
import javax.persistence.*;
#Entity
#Table(name="faq")
public class FAQ {
#Id
private int id_qr;
private int id_technicien;
private String question;
private String reponse;
public int getId_qr() {
return id_qr;
}
public void setId_qr(int id_qr) {
this.id_qr = id_qr;
}
public int getId_technicien() {
return id_technicien;
}
public void setId_technicien(int id_technicien) {
this.id_technicien = id_technicien;
}
public String getQuestion() {
return question;
}
public void setQuestion(String question) {
this.question = question;
}
public String getReponse() {
return reponse;
}
public void setReponse(String reponse) {
this.reponse = reponse;
}
}
This is the DAO class:
The function public List<FAQ> chargerFAQ() is supposed to return a list of FAQ.
The JPQL query is: private static final String JPQL_SELECT_ALL = "SELECT f FROM FAQ f";
`package projet.helpdesk.dao;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import projet.helpdesk.beans.FAQ;
#Stateless
public class FAQDao {
private static final String JPQL_SELECT_ALL = "SELECT f FROM FAQ f";
private static final String JPQL_SELECT_QR = "SELECT f FROM FAQ f WHERE id_qr=:id_qr";
private static final String PARAMETER = "id_qr";
#PersistenceContext( unitName = "bdd_helpdesk_PU" )
private EntityManager em;
public void creer( FAQ faq ) throws IllegalArgumentException, DAOException {
try {
em.persist(faq);
} catch ( Exception e ) {
throw new DAOException( e );
}
}
public List<FAQ> chargerFAQ() throws DAOException {
List<FAQ> listefaq;
Query query = em.createQuery(JPQL_SELECT_ALL);
try {
listefaq = (List<FAQ>) query.getResultList();
} catch ( NoResultException e ) {
return null;
} catch(Exception e) {
throw new DAOException(e);
}
return listefaq;
}
public FAQ trouverQR(int id_qr) throws DAOException{
FAQ qr;
Query query = em.createQuery(JPQL_SELECT_QR);
query.setParameter(PARAMETER, id_qr);
try {
qr = (FAQ) query.getSingleResult();
} catch ( NoResultException e ) {
return null;
} catch(Exception e) {
throw new DAOException(e);
}
return qr;
}
}
`
Persisting the FAQ entity was successful, but loading the data does'nt return anything, maybe the query instruction is wrong?
Here's the servlet:
`#WebServlet ( urlPatterns = { "/afficherfaq" })
public class AfficherFaq extends HttpServlet {
#EJB
private FAQDao faqDao;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.getServletContext().getRequestDispatcher("/WEB-INF/ChargerFaq.jsp").forward(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
List<FAQ> lfaq = faqDao.chargerFAQ();
request.setAttribute("lfaq", lfaq);
this.getServletContext().getRequestDispatcher("/WEB-INF/ChargerFaq.jsp").forward(request, response);
}
}
`
And the Entity's path is included in the persistence.xml file.
EDIT: Added JSP code.
JSP file to show the result:
<%# page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link type="text/css" rel="stylesheet" href="inc/style.css" />
<title>Foire aux questions</title>
</head>
<body>
Test
<c:forEach items="${lfaq}" var="faq" varStatus="boucle">
<fieldset>
<p><span class="info">Question:</span></p><br>
<p>${faq.question}</p><br>
<p><span class="info">Reponse:</span></p><br>
<p>${faq.reponse}</p><br>
</fieldset><br><br>
</c:forEach>
</body>
</html>
So .. I have two tables Utilisateur and ReponsesTickets ( there's no trouble inserting selecting updating deleting from each table by itself) to make a join between these two tables i had to create a new Entity here's its code.
package projet.helpdesk.beans;
import java.sql.Timestamp;
//TEXTE - DATE_POST - NOM - PRENOM - AGENCE - POSTE - DEPARTEMENT - ID_EMPLOYE
public class Jointure1 {
private String texte;
private String nom;
private String prenom;
private String Agence;
private String poste;
private String departement;
private int id_employe;
private Timestamp date_post;
public String getTexte() {
return texte;
}
public void setTexte(String texte) {
this.texte = texte;
}
public String getNom() {
return nom;
}
public void setNom(String nom) {
this.nom = nom;
}
public String getPrenom() {
return prenom;
}
public void setPrenom(String prenom) {
this.prenom = prenom;
}
public String getAgence() {
return Agence;
}
public void setAgence(String agence) {
Agence = agence;
}
public String getPoste() {
return poste;
}
public void setPoste(String poste) {
this.poste = poste;
}
public String getDepartement() {
return departement;
}
public void setDepartement(String departement) {
this.departement = departement;
}
public int getId_employe() {
return id_employe;
}
public void setId_employe(int id_employe) {
this.id_employe = id_employe;
}
public Timestamp getDate_post() {
return date_post;
}
public void setDate_post(Timestamp date_post) {
this.date_post = date_post;
}
}
That's the SQL instruction i'm trying to translate into JPQL.
SELECT u.nom, u.prenom, r.texte, r.date_post
FROM Utilisateur u, ReponseTicket r
WHERE u.id_emp = r.id_employe
AND r.id_ticket = ? ( parameter here )
This is the method in the DAO pattern.
private static final String PARAM_TICKET = "id_ticket";
private static final String JPQL_SELECT ="SELECT u.nom, u.prenom, r.texte, r.date_post FROM Utilisateur u JOIN ReponseTicket r ON u.id_emp = r.id_employe AND r.id_ticket=:id_ticket";
//^ Above is the JPQL instruction, not sure if it's correct.
#PersistenceContext( unitName = "bdd_helpdesk_PU" )
private EntityManager em;
public List<Jointure1> trouverJointure( int id_ticket ) throws DAOException {
List<Jointure1> liste;
TypedQuery<Jointure1> query = em.createQuery(JPQL_SELECT, Jointure1.class);
query.setParameter(PARAM_TICKET, id_ticket);
try {
liste = (List<Jointure1>) query.getResultList();
} catch ( NoResultException e ) {
return null;
} catch(Exception e) {
throw new DAOException(e);
}
return liste;
}
Then goes the ResponseForm that communicates with the DAO method.
this method collects the ticket id from the request and passes it to the DAOmethod to insert it into the JPQL instruction.
public List<Jointure1> recupererJointure(HttpServletRequest request)
{
List<Jointure1> ljointure;
int id = getId_ticket(request);
if(id!=0){
ljointure = reponseDao.trouverJointure(id);
}else ljointure=null;
return ljointure;
}
Stacktrace:
Caused by: Exception [EclipseLink-6168] (Eclipse Persistence Services - 2.6.1.v20150605-31e8258): org.eclipse.persistence.exceptions.QueryException
Exception Description: Query failed to prepare, unexpected error occurred: [java.lang.NullPointerException].
Internal Exception: java.lang.NullPointerException
Query: ReportQuery(referenceClass=Utilisateur jpql="SELECT u.nom, u.prenom, r.texte, r.date_post FROM Utilisateur u JOIN ReponseTicket r ON u.id_emp = r.id_employe AND r.id_ticket=:id_ticket")
I don't know about the null pointer exception, the parameter id_ticket is visible in the URL.
However i didn't add the new Entity in the persistence.xml
http://localhost:4040/monprojet2/reponsesticket?id_ticket=62
This is the servlet.
package projet.helpdesk.servlets;
#WebServlet(urlPatterns={"/reponsesticket"})
public class Reponsestickets extends HttpServlet {
#EJB
private TicketDao ticketDao;
#EJB
private ReponseTicketDao reponseDao;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
CreationTicketForm ticketform = new CreationTicketForm(ticketDao);
Ticket ticket = ticketform.recupererTicket(request);
CreationReponseForm reponse = new CreationReponseForm(reponseDao);
List<Jointure1> listereponse = reponse.recupererJointure(request);
if(ticket==null)
{
response.sendRedirect("/connexion");
} else {
request.setAttribute("lreponse", listereponse);
request.setAttribute("ticket", ticket);
this.getServletContext().getRequestDispatcher("/WEB-INF/ReponsesTickets.jsp").forward(request, response);
}
}
}
EDIT:
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Réponses ticket</title>
<meta http-equiv="Content-Type" content="text/html">
<link type="text/css" rel="stylesheet" href="inc/style.css" />
</head>
<body>
<p>Test---> <br>votre id:${masession.idemp}<br>
Type:${masession.type}<br>
</p>
<fieldset>
<legend>Réponses pour ticket id: ${ticket.id_ticket}</legend><br>
<p>Sujet:</p> ${ticket.sujet} <br>
<p>Description:</p> ${ticket.description}<br>
</fieldset>
<br>
<c:forEach items="${lreponse}" var="reponse">
<p>Nom: ${reponse.nom}</p>
<p>Prenom: ${reponse.prenom }</p>
<p>Réponse: ${reponse.texte }</p>
<p>Date: ${reponse.date_post }</p>
<br><br>
</c:forEach>
<br><br><br>
<fieldset>
<legend>Répondre:</legend>
<form method="post" action="creerreponse" enctype="application/x-www-form-urlencoded">
<textarea rows="5" cols="36" name="texte"></textarea>${erreurs['texte']}<br/>
<input type="hidden" name="id_employe" value="${masession.idemp}">
<input type="hidden" name="id_ticket" value="${ticket.id_ticket}">
<input type="hidden" name="type" value="${masession.type}">
<input type="submit" value="Valider"><br/>
</form>
<p></p>
</fieldset>
</body>
</html>
Stacktrace:
[2017-05-03T16:47:49.790+0100] [glassfish 4.1] [WARNING] [] [javax.enterprise.web] [tid: _ThreadID=30 _ThreadName=http-listener-1(4)] [timeMillis: 1493826469790] [levelValue: 900] [[
StandardWrapperValve[projet.helpdesk.servlets.Reponsestickets]: Servlet.service() for servlet projet.helpdesk.servlets.Reponsestickets threw exception
java.lang.NumberFormatException: For input string: "nom"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
at java.lang.Integer.parseInt(Integer.java:615)
at javax.el.ArrayELResolver.toInteger(ArrayELResolver.java:378)
at javax.el.ArrayELResolver.getValue(ArrayELResolver.java:198)
at javax.el.CompositeELResolver.getValue(CompositeELResolver.java:188)
at com.sun.el.parser.AstValue.getValue(AstValue.java:140)
at com.sun.el.parser.AstValue.getValue(AstValue.java:204)
at com.sun.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:226)
at org.jboss.weld.el.WeldValueExpression.getValue(WeldValueExpression.java:50)
at org.apache.jasper.runtime.PageContextImpl.evaluateExpression(PageContextImpl.java:1016)
at org.apache.jsp.WEB_002dINF.ReponsesTickets_jsp._jspx_meth_c_forEach_0(ReponsesTickets_jsp.java:143)
at org.apache.jsp.WEB_002dINF.ReponsesTickets_jsp._jspService(ReponsesTickets_jsp.java:85)
My project is a spring mvc project.In my project i have a domain Technology which has foreign key reference.When i validating on form submit it threw error....For view part(jsp),i using form:select for viewing department in technology.
How can i validate a foreign reference?????
i tried below code
domain
#Entity
#Table(name = "technology")
public class Technology {
private int id;
#NotEmpty
private String name;
#NotEmpty
private Department department;
private Date createdDate;
private boolean isDelete;
}
message.properties
NotEmpty.technology.department=Required!
Technology.jsp
<form:form method="post" action="add-technology"
commandName="technology" id="technologyForm">
<label>Technology Name</label>
<form:input path="name" /><form:errors path="name" class="error"></form:errors>
<br />
<label>Department</label>
<form:select path="department.id">
<form:option value="0" label="Select" />
<form:options items="${departments}" itemValue="id" itemLabel="name" />
</form:select><form:errors path="department" class="error"></form:errors>
<%-- <form:select path="department.id" items="${departments}" /> --%>
<input type="submit" class="btn btn-primary"/>
</form:form>
controller
#RequestMapping(value = "/add-technology")
public String addTechnology(
#ModelAttribute(value = "technology")#Valid Technology technology,
BindingResult result) {
if(result.hasErrors()){
return "/secure/admin/technology";
}
java.util.Date utilDate = new java.util.Date();
Date sqlDate = new Date(utilDate.getTime());
technology.setCreatedDate(sqlDate);
technologyService.saveTechnology(technology);
return "redirect:/technologies";
}
ERROR
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is javax.validation.UnexpectedTypeException: No validator could be found for type: com.company.product.domain.Department
How can i resolve this problem???
Here you have to implement validator for Technology object
class TechnologyValidator extends Validator {
public boolean supports(Class<?> cls) {
return Technology .class.equals(cls);
}
public void validate(Object target, Errors errors) {
super.validate(target, errors);
Technology tecObj= (Technology ) target;
//here i am assuming Technology name is REQUIRED and
//NotEmpty.technology.name is in message.properties
ValidationUtils.rejectIfEmptyOrWhitespace(errors,"name",
"NotEmpty.technology.name");
Department dept = tecObj.getDepartment();
//as from from your are binding department ID
if (dept==null || dept.getId()==null || dept.getId()==0L ) {
errors.rejectValue("department.id", "NotEmpty.technology.department");
}
}
}
And create bean of this class in Spring-context
#Autowired
TechnologyValidator techValid;
And call this validator in your controller like
#RequestMapping(value = "/add-technology")
public String addTechnology(
#ModelAttribute(value = "technology") Technology technology,
BindingResult result) {
//call validator
techValid.validate(technology, result);
if(result.hasErrors()){
return "/secure/admin/technology";
}
java.util.Date utilDate = new java.util.Date();
Date sqlDate = new Date(utilDate.getTime());
technology.setCreatedDate(sqlDate);
technologyService.saveTechnology(technology);
return "redirect:/technologies";
}
I'm working on a project. I need to get a list from MySql database and list it. I'm using JSF 2.1 Primeface 3.5 and Eclipse Juno. I run my code but it doesn't work. You can see my codes in below
//LOGIN CLASS
import parts
#ManagedBean
#SessionScoped
public class Login {
private String username, password;
private PreparedStatement ps, ps2;
private ResultSet rs, rs2;
private List<Application> applications = new ArrayList<Application>();;
private Application selectedApplication;
// GETTERS SETTERS
public String login() {
Connection object = new Connection();
try {
ps = nesne
.getCon()
.prepareStatement(
"select Username, Password from company where Username=? and Password=?");
ps.setString(1, getUsername());
ps.setString(2, getPassword());
rs = ps.executeQuery();
while (rs.next()) {
getList();
return "application";
}
} catch (Exception e) {
System.err.println(e);
}
return "confirm";
}
private List<Application> getList() {
Baglanti nesne = new Baglanti();
try {
ps2 = nesne
.getCon()
.prepareStatement(
"select ApplicationName from application where CompanyID=(select ID from company "
+ "where Username=? and Password=?)");
ps2.setString(1, getUsername());
ps2.setString(2, getPassword());
rs2 = ps2.executeQuery();
while (rs2.next()) {
Application obj = new Application();
obj.setApplicationName(rs2.getString("ApplicationName"));
applications.add(obj);
}
} catch (Exception e) {
System.err.println(e);
}
return applications;
}
APPLICATION CLASS
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean
#SessionScoped
public class Application {
private int ID;
private int CompanyID;
private String Type;
private Date Date;
private String ApplicationName;
private int CurrentMessageCount;
private int MaxMessage;
private String isPro;
//GETTERS SETTERS
application.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>Login Confirmed</title>
</h:head>
<h:body>
<h1 class="ui-widget-header ui-corner-all" align="center">Application
List</h1>
<br />
<h:form id="form">
<p:growl id="msgs" showDetail="true" />
<p:dataTable id="applications" var="application"
value="#{login.applications}">
<p:column headerText="Application" style="width:24%">
<h:outputText value="#{login.applications}" />
</p:column>
<p:column style="width:4%">
<p:commandButton id="selectButton" icon="ui-icon-search"
title="View">
<f:setPropertyActionListener value="#{application}"
target="#{login.selectedApplication}" />
</p:commandButton>
</p:column>
</p:dataTable>
</h:form>
I can login properly after that ı saw this page.
Now where is my mistake?
Your var="application" is conflicting with the implicit EL object referring the application context (the ServletContext). You can find here a list of all implicit EL objects. Memorize them. You should never declare an EL variable on exactly those names.
Give it a different name. E.g. var="app", var="_application", etc.
In data table var property mean that every item from database will be accesible as this "var" value. i.e:
You have class Foo:
class Foo{
int number;
String text;
//Setters and getters
}
And another class which handle list of Foo objects (your model as CDI Bean):
#Named
class Boo{
List<Foo> list = new ArrayList<>();
//Getter and setters
}
So to list it all in jsf page you should use it like this:
<p:dataTable id="list" var="listobject" value="#{boo.list}">
<p:column headerText="Number" style="width:24%">
<h:outputText value="#{listobject.number}" />
</p:column>
<p:column headerText="Text" style="width:24%">
<h:outputText value="#{listobject.String}" />
</p:column>
</p:dataTable>
So summary "var" value is accessor string to boo object.
Look also:
PrimeFaces datatable demo and here
Mkyong datatable tutorial
I already searched and found several approaches here, but I can't get them working for my project.
I want to show an edit page for a list of objects, which should all be updated at once. I use the model driven architecture approach to achieve this, but I can't get it running properly. I can always display and iterate the list and its values, but I can't modify its values.
So here is what I'm currently doing:
I have a Model 'Teilzeitgrad' in my database, which has some simple attributes with getters and setters.
public class Teilzeitgrad {
private Date datumAb;
private Date datumBis;
private double betrag;
// ... getters and setters
}
In my Action-Class I implement the ModelDriven Interface with a List of Teilzeitgrad-Objects
public class DienstabschnittViewJahrAction implements ModelDriven<List<Teilzeitgrad>>, Preparable
{
List<Teilzeitgrad> teilzeitgrads;
private String tzgTypKey;
private Integer jahrIndex;
public String execute() {
return SUCCESS;
}
public List<Teilzeitgrad> getModel()
{
if(teilzeitgrads == null) {
teilzeitgrads = getTeilzeitgradListByTypAndJahr(getTzgTypKey(), getJahrIndex());
}
return teilzeitgrads;
}
public List<Teilzeitgrad> getTeilzeitgrads()
{
return teilzeitgrads;
}
public void setTeilzeitgrads(List<Teilzeitgrad> teilzeitgrads)
{
this.teilzeitgrads = teilzeitgrads;
}
#Override
public void prepare() throws Exception
{
// TODO Auto-generated method stub
}
public String getTzgTypKey()
{
return tzgTypKey;
}
public void setTzgTypKey(String tzgTypKey)
{
this.tzgTypKey = tzgTypKey;
}
public Integer getJahrIndex()
{
return jahrIndex;
}
public void setJahrIndex(Integer jahrIndex)
{
this.jahrIndex = jahrIndex;
}
}
The action mapping in struts.xml is defined as follows:
<action name="*/auth/GroupAdmin/processEditDienstabschnittJahr" method="execute" class="org.hocon.ul.portal.action.DienstabschnittViewJahrAction">
<result name="success" type="redirect">${referer}</result>
</action>
In my JSP File I'm iterating the model object, displaying its values in textfields or lists as follows:
<ul:form action="auth/GroupAdmin/processEditDienstabschnittJahr">
<s:iterator value="model" status="rowStatus">
<tr>
<td style="text-align: center;">
<s:date name="model.get(#rowStatus.index).datumAb" var="datumAb_DE" format="dd.MM.yyyy" />
<s:textfield style="width:70px;" name="model.get(#rowStatus.index).datumAb" value="%{#datumAb_DE}" label="DatumAb"></s:textfield >
</td>
<td style="text-align:center;">
<s:date name="model.get(#rowStatus.index).datumBis" var="datumBis_DE" format="dd.MM.yyyy" />
<s:textfield style="width:70px;" name="model.get(#rowStatus.index).datumBis" value="%{#datumBis_DE}" label="DatumBis"></s:textfield >
</td>
<td class="currency">
<s:set var="tzgBetrag">
<fmt:formatNumber type="NUMBER" maxFractionDigits="0"><s:property value="%{getBetrag()*100}"></s:property></fmt:formatNumber>
</s:set>
<s:textfield style="width:30px;" maxlength="3" name="model.get(#rowStatus.index).betrag" value="%{#tzgBetrag}" label="Betrag"></s:textfield >
</td>
</tr>
</s:iterator>
<s:submit style="width:24px; height:24px;" type="image" src="../../../res/24px/floppy-disk.png" value="Speichern"></s:submit>
</ul:form>
The ul-tag is from a custom taglib, which adds a customer specific url parameter to action path.
So when I display the page it shows all my Teilzeitgrad-records with a row for each entry. But when I submit the form, the list of my models is not populated. The setter setTeilzeitgrads(List<Teilzeitgrad> teilzeitgrads) is not even called at all.
I also tried to access the list in array-syntax:
<s:textfield style="width:70px;" name="teilzeitgrads[#rowStatus.index].datumAb" value="%{#datumAb_DE}" label="DatumAb"></s:textfield >
but this did also not work.
Any help solving this case is apreciated! Thanks in advance!
Lenzo
Ok - here is a very basic working example of list indexing. The main change is to move the creation of the model from getModel() to prepare(). This is because getModel() is called for every value you need to set the list - so you end up re-creating your model each time overwriting the previous change.
package com.blackbox.x.actions;
import java.util.ArrayList;
import java.util.List;
import com.blackbox.x.actions.ListDemo.ValuePair;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import com.opensymphony.xwork2.Preparable;
public class ListDemo extends ActionSupport implements ModelDriven<List<ValuePair>>, Preparable {
private List<ValuePair> values;
#Override
public List<ValuePair> getModel() {
return values;
}
public String execute() {
for (ValuePair value: values) {
System.out.println(value.getValue1() + ":" + value.getValue2());
}
return SUCCESS;
}
public void prepare() {
values = new ArrayList<ValuePair>();
values.add(new ValuePair("chalk","cheese"));
values.add(new ValuePair("orange","apple"));
}
public class ValuePair {
private String value1;
private String value2;
public ValuePair(String value1, String value2) {
this.value1 = value1;
this.value2 = value2;
}
public String getValue1() {
return value1;
}
public void setValue1(String value1) {
this.value1 = value1;
}
public String getValue2() {
return value2;
}
public void setValue2(String value2) {
this.value2 = value2;
}
}
}
and the corresponding jsp
<%# taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
</head>
<body>
<s:form action="list-demo" theme="simple">
<table>
<s:iterator value="model" status="rowStatus">
<tr>
<td><s:textfield name="model[%{#rowStatus.index}].value1" value="%{model[#rowStatus.index].value1}"/></td>
<td><s:textfield name="model[%{#rowStatus.index}].value2" value="%{model[#rowStatus.index].value2}"/></td>
</tr>
</s:iterator>
</table>
<s:submit/>
</s:form>
</body>
</html>
Have you tried an approach like this?
<s:iterator var="teilzeitgrad" value="teilzeitgrads" status="listStatus">
<s:set name="paramName">teilzeitgrads[${ listStatus.index }].datumAb</s:set>
<s:textfield name="%{#paramName}" value="%{#teilzeitgrad.datumAb}"/>
</s:iterator>
You are submitting values to model, you have to submit them to your list teilzeitgrads.
For example see http://www.dzone.com/tutorials/java/struts-2/struts-2-example/struts-2-model-driven-action-example-1.html.
Update
How about
name="teilzeitgrads[%{#rowStatus.index}].datumBis".
Assuming you've got the configuration correct - the problem is probably due to the way you're defining the indexing. Try changing the name attribute on the textfield to use
model[%{#rowStatus.index}].datumBis
and let OGNL sort out the access methods. (I'd also use Firebug in Firefox to see what is actually being sent when you submit the form)
Thanks to all of you getting along with this issue! Your hints were most useful. I finally got it up and running rewriting everything from the scratch. I can edit my models now using the following Action-Class:
public class TeilzeitgradEditAction implements ModelDriven<List<Teilzeitgrad>> {
List<Teilzeitgrad> teilzeitgrads;
private String tzgTypKey;
private Integer jahr;
public String execute() {
return SUCCESS;
}
#Override
public List<Teilzeitgrad> getModel()
{
if(teilzeitgrads == null) {
teilzeitgrads = getTeilzeitgradListByTypAndJahr(tzgTypKey, jahr);
}
return teilzeitgrads;
}
public List<Teilzeitgrad> getTeilzeitgrads()
{
return teilzeitgrads;
}
public void setTeilzeitgrads(List<Teilzeitgrad> teilzeitgrads)
{
this.teilzeitgrads = teilzeitgrads;
}
// getters and setters for local attributes
}
and this JSP-Code:
<ul:form action="auth/GroupAdmin/processEditDienstabschnittJahr">
<s:iterator var="teilzeitgrad" value="teilzeitgrads" status="listStatus">
<tr>
<td>
<s:date name="%{#teilzeitgrad.datumAb}" var="datumAb_DE" format="dd.MM.yyyy" />
<s:textfield name="teilzeitgrads[%{#listStatus.index}].datumAb" value="%{#datumAb_DE}"/>
</td>
</tr>
</s:iterator>
<s:submit style="width:24px; height:24px;" type="image" src="../../../res/24px/floppy-disk.png" value="Speichern"></s:submit>
Thanks a lot for your support!
Cheers,
Lenzo