I really new in Java....i work some research in java using tool Tapestry framework...
I have some problem with exception when i calling #Component "Form"...tapestry throws me exception :
Embedded component(s) loginForm are defined within component class com.fit.pages.Login (or a super-class of Login), but are not present in the component template (classpath:com/fit/pages/Login.tml).
context
eventType
activate
org.apache.tapestry5.ioc.internal.OperationException
Embedded component(s) loginForm are defined within component class com.fit.pages.Login (or a super-class of Login), but are not present in the component template (classpath:com/fit/pages/Login.tml).
trace
**Triggering event 'activate' on Index
Constructing instance of page class com.fit.pages.Login
Creating ComponentAssembler for com.fit.pages.Login**
my code looks something like this
public class Login {
private String userName;
#Property
private String password;
#Inject
#Property
private Users users;
#SessionState
private User user;
#Component(id="loginForm")
private Form loginForm;
#Inject
private Messages messages;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
void onValidate(){
User authenticatedUser = Security.authenticate(userName, password, users);
if(authenticatedUser != null){
user = authenticatedUser;
}else{
loginForm.recordError(messages.get("authentication-failed"));
}
}
#OnEvent
Object onSubmit(){
System.out.println("form was submited");
Class nextPage = null;
User authenticatedUser = Security.authenticate(userName, password, users);
if(authenticatedUser != null){
user = authenticatedUser;
nextPage = Index.class;
} else {
nextPage = Registration.class;
}
return nextPage;
}
and code in login.tml :
Please log in:
<t:form id="loginForm">
<table>
<tr>
<td>
<t:label t:for="userName"/>:
</td>
<td>
<input type="text" t:type="textfield" t:id="userName"
t:value="userName" t:validate="required"/>
</td>
</tr>
<tr>
<td>
<t:label t:for="password"/>:
</td>
<td>
<input type="text" t:type="passwordfield" t:id="password"
t:value="password" t:validate="required"/>
</td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="Log In"/>
</td>
</tr>
</table>
</t:form>
replace
<t:form id="loginForm">
with
<t:form t:id="loginForm">
Related
I'm getting an error NotReadablePropertyException: Invalid property 'userIds' of bean class [...ListOfIds]... And I'm not sure why. If I remove the th:field attribute on the checkbox, the table fills in properly. I've tried with th:field="*{requestIds}" and th:field="*{requestIds.ids}"
What I'm trying to do is collect the list of ids from the selected checkboxes and pass them back to the controller for the post.
Form
public class ListOfIds {
List<Long> ids = new ArrayList<>();
public List<Long> getIds() { return ids; }
// I've tried both set methods by themselves and together.
public void setIds(List<Long> ids) { this.ids = ids; }
public void setIds(Long[] ids) { this.ids = Arrays.asList(ids); }
}
Request bean
public class Request {
long id;
String name;
String phone;
String email;
// Getters/Setters
}
Controller
#GetMapping("/myTable")
public ModelAndView getMyTable(ModelAndView mav) {
mav.setViewName("myTable");
List<Request> requests = service.getRequests();
mav.addObject("requests", requests);
mav.addObject("requestIds", new ListOfIds());
return mav;
}
#PostMapping("/myTable")
public ModelAndView postRequests(ModelAndView mav, #ModelAttribute("requestIds") ListOfIds ids) {
...
}
html page
...
<form method="post" th:action="#{/myTable}" th:object="${requestIds}">
<table class="table ...">
<thead>
<tr>
<th><input type="checkbox" class="selectall" data-target="requests-all"/></th>
<th>Name</th>
<th>Phone</th>
<th>Email</th>
</tr>
</thead>
<tbody>
<tr role="row" th:each="request : ${requests}">
<td>
<input type="checkbox" name="requestId" data-target="requests-all"
th:value="${request.id}" th:field="*{requestIds}"/>
</td>
<td th:text="${request.name}"></td>
<td th:text="${request.phone}"></td>
<td th:text="${request.email}"></td>
</tr>
</tbody>
</table>
<button class="btn btn-primary show-selected">Process</button>
</form>
...
<script>
$(document).ready(function() {
$('button').click(function(e) {
if !(confirm("Are you sure you wish to process these requests")) {
e.preventDefault();
}
});
});
</script>
...
So the answer is that name and th:field don't play nice together.
I made the following changes and it worked:
Controller
#PostMapping("/myTable")
public ModelAndView postRequests(ModelAndView mav,
#ModelAttribute("requestIds") Long[] ids) {
...
}
html
<form id="postMyTable" method="post" th:action="#{/myTable}">
<table ...
<input type="checkbox" name="requestId" data-target="requests-all"
th:value="${request.id}"/>
...
<script>
$(document).ready(function() {
$('button').click(function(e) {
if !(confirm("Are you sure you wish to process these requests")) {
e.preventDefault();
} else {
$("#postMyTable").submit();
}
});
});
</script>
My user is adding an exam object which is then added to the subject object. Subject and exam have a one to many relationship.
The user is selecting the subject in the drop down menu.This menu contains string not actual subject objects.
In this form, how do I send an exam object and the selected item (String) to the controller?
My HTML file
<form action="#" th:action="#{/addExam}" th:object="${exam}"
method="post">
<div th:object="${subject}">
<select th:field="*{option}" class="form-control" id="subjectOrder"
name= "subjectOrder">
<option value="">Select subject</option>
<option
th:each="Subject : ${subjects}"
th:value="${Subject}"
th:text="${Subject}"></option>
</div>
<div>
<table>
<tr>
Exam Title
<td><input type="text" th:field="*{examTitle}" /></td>
</tr>
<tr>
<td> Exam grade worth </td>
<td><input th:field="*{examGradeWorth}" /></td>
</tr>
<tr>
<td><button type="submit">Submit post</button></td>
</tr>
</table>
</div>
</form>
The controller, I want to set subject Name to equal the subject the user selected in the drop down box.
#GetMapping("/addexam")
public String showExamForm(Model model) {
Authentication loggedInUser =
SecurityContextHolder.getContext().getAuthentication();
String email = loggedInUser.getName();
User user = userRepository.findByEmailAddress(email);
ArrayList<String> subjects = new ArrayList<String>();
for(Subject sub:user.getSubject())
{
subjects.add(sub.getSubjectName());
}
model.addAttribute("subjects", subjects);
return "addExam";
}
#PostMapping("/addexam")
public String addNewExam(#ModelAttribute("exam") #Valid #RequestBody Exam
exam,UserRegistrationDto userDto, BindingResult result, Model model) {
examRepository.save(exam);
model.addAttribute("examTitle", exam.getExamTitle());
model.addAttribute("examGradeWorth", exam.getExamGradeWorth());
String subjectName = ();
//I want to set subjectName to equal the selected option.
Subject subject = subjectRepository.findBySubjectName(subjectName);
subject.addExam(exam);
subjectRepository.save(subject);
return "userProfile1";
}
I managed to find the selected value.
See my code below.
Exam Controller:
#Controller
public class AddExamController {
#Autowired
private ExamRepository examRepository;
#Autowired
private SubjectRepository subjectRepository;
#Autowired
private UserRepository userRepository;
#ModelAttribute("exam")
public Exam exam() {
return new Exam();
}
#GetMapping("/addexam")
public String showExamForm(Model model) {
Authentication loggedInUser = SecurityContextHolder.getContext().getAuthentication();
String email = loggedInUser.getName();
User user = userRepository.findByEmailAddress(email);
ArrayList<String> subjects = new ArrayList<String>();
for(Subject sub:user.getSubject())
{
subjects.add(sub.getSubjectName());
}
model.addAttribute("subjects", subjects);
return "addExam";
}
#PostMapping("/addExam") //This was causing one problem i was getting. I had it as /addexam and it should have been addExam
public String addNewExam(#ModelAttribute("exam") #Valid #RequestBody Exam exam,UserRegistrationDto userDto, BindingResult result, Model model) {
examRepository.save(exam);
model.addAttribute("examTitle", exam.getExamTitle());
model.addAttribute("examGradeWorth", exam.getExamGradeWorth());
model.addAttribute("subject", "");
//String subjectName = ("subject", exam.getSubject());
// Subject subject = subjectRepository.findBySubjectName(subjectName);
//subject.addExam(exam);
/// subjectRepository.save(subject);
return "userProfile1";
}
}
HTML
<form action="#" th:action="#{/addExam}" th:object="${exam}" method="post">
<select th:field="*{subject}" class="form-control" id="subject" name="subject">
<option value="">Select subject</option>
<option
th:each="Subject : ${subjects}"
th:value="${Subject}"
th:text="${Subject}"></option>
<table>
<tr>
<td> Exam Title:</td>
<td><input type="text" th:field="*{examTitle}" /></td>
</tr>
<tr>
<td> Exam grade worth </td>
<td><input th:field="*{examGradeWorth}" /></td>
</tr>
<tr>
<td><button type="submit">Submit post</button></td>
</tr>
</table>
</div>
</form>
I'm having problems with validating in Spring. I'm getting the following error after opening the form:
java.lang.IllegalStateException: Invalid target for Validator [com.example.validator.UserValidator#6ac0a8f4]: com.example.web.forms.UserDTO#4d3b2379
My Validator for the time being, wanted to check if anything works first:
#Component
public class UserValidator implements Validator {
#Autowired
ServiceUser serviceUser;
#Override
public boolean supports(Class<?> clazz) {
return User.class.equals(clazz);
}
#Override
public void validate(Object target, Errors errors) {
User user = (User) target;
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "NotEmpty.userForm.name");
}
}
Controller:
#Controller
public class UserController {
#Autowired
UserValidator userValidator;
#InitBinder
public void initBinder(WebDataBinder binder) {
CustomDateEditor editor = new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true, 10);
binder.registerCustomEditor(Date.class, editor);
binder.setValidator(userValidator);
// binder.addValidators(userValidator);
}
final static Logger logger = Logger.getLogger(UserController.class);
#Autowired
protected ServiceUserImpl service;
#RequestMapping("/lista")
public String showIndex(Model model) {
User contest = new User();
model.addAttribute("element", contest);
model.addAttribute("collection", service.findAll());
return "lista";
}
#RequestMapping("/dodaj")
public String showFormPublication(HttpServletRequest request, #ModelAttribute("userDto") #Valid UserDTO userDTO, BindingResult result) {
if (request.getMethod().equalsIgnoreCase("post") && !result.hasErrors()) {
if (result.hasErrors()) {
return "forms/contest";
} else {
User user = new User();
user.setId(userDTO.getId());
user.setName(userDTO.getName());
user.setSurname(userDTO.getSurname());
user.setDateOfBirth(userDTO.getDateOfBirth());
user.setIndexNumber(userDTO.getIndexNumber());
user.setEmail(userDTO.getEmail());
service.save(user);
return "redirect:/lista";
}
}
return "dodaj";
}
}
Form in .jsp:
<form:form action="dodaj" method="POST" modelAttribute="userDto">
<table border="1">
<tbody>
<tr>
<th>ImiÄ™</th>
<td>
<form:input type="text" path="name" />
<c:if test="${pageContext.request.method=='POST'}"><form:errors path="name" /></c:if>
</td>
</tr>
<tr>
<th>Nazwisko</th>
<td>
<form:input type="text" path="surname" />
<c:if test="${pageContext.request.method=='POST'}"><form:errors path="surname" /></c:if>
</td>
</tr>
<tr>
<th>DataUrodzenia</th>
<td>
<form:input type="date" path="dateOfBirth" />
<c:if test="${pageContext.request.method=='POST'}"><form:errors path="dateOfBirth" /></c:if>
</td>
</tr>
<tr>
<th>NumerIndeksu</th>
<td>
<form:input type="number" path="indexNumber" />
<c:if test="${pageContext.request.method=='POST'}"><form:errors path="indexNumber" /></c:if>
</td>
</tr>
<tr>
<th>Email</th>
<td>
<form:input type="text" path="email" />
<c:if test="${pageContext.request.method=='POST'}"><form:errors path="email" /></c:if>
</td>
</tr>
<tr>
<td colspan="2" align="right"><input type="submit" value="Dodaj!" /></td>
</tr>
</tbody>
</table>
</form:form>
I tried adding ("userDto") next to #InitBinder, it didn't help unfortunately. Haven't found much more in terms of applicable solutions. If there's anything else I should post here let me know. I can also provide a link to repository should anyone be eager enough to try to run it.
I think you need to change the supports method in UserValidator to UserDTO class:
public boolean supports(Class<?> clazz) {
return UserDTO.class.equals(clazz);
}
In my program, I am generating dynamic form names based on the number of feedbacks I get. I am then taking the satisfaction, comment and feedbackId inputs. They are different for each iteration. This is giving me an IllegalStateException error.
My HTML form is:
<form action="#" th:action="#{/heart2heart/token/__${tokenId}__/}" method="post">
<div class="table-responsive">
<table class="table table-striped table-bordered table-hover table-condensed">
<tr>
<th style="display:none;"></th>
<th th:text="#{service.desc}">Service</th>
<th th:text="#{feedback.description}">Feedback</th>
<th th:text="#{visit.date}">Date of Visit</th>
<th th:text="#{repr.name}">FU Repr</th>
<th th:text="#{resolution.response}">Response</th>
<th th:text="#{resolution.satisfactionLevel}">Satisfaction</th>
<th th:text="#{resolution.comment}">Comment</th>
</tr>
<tr th:each="feedback, feedbackStat : *{feedbacks}">
<td style="display:none;"><input type="hidden" th:field="*{feedbacks[__${feedbackStat.index}__].feedbackId}" th:value="${feedback.id}" /></td>
<td th:text="${feedback.service.description}">Steel</td>
<td th:text="${feedback.description}">Problem</td>
<td th:text="${feedback.visits[0].date}">12/08/2015</td>
<td th:text="${feedback.visits[0].repr.fullName}">XYZ</td>
<td th:text="${feedback.receipt.resolutions[0].response}">response</td>
<td>
<div class="radio">
<label><input type="radio" th:field="*{feedbacks[__${feedbackStat.index}__].satisfaction}" th:text="#{global.yes}" value="SATISFIED">Yes</input></label>
</div>
<div class="radio">
<label><input type="radio" th:field="*{feedbacks[__${feedbackStat.index}__].satisfaction}" th:text="#{global.no}" value="NOT SATISFIED">No</input></label>
</div>
</td>
<td><textarea th:field="*{feedbacks[__${feedbackStat.index}__].comment}" class="form-control" rows="2"></textarea></td>
</tr>
</table>
<div class="form-group">
<button type="submit" name="addRow" th:text="#{button.submit}"
class="btn btn-primary btn-md">Submit</button>
</div>
</div>
</form>
My controller is:
#RequestMapping(value = "/{tokenId}/", method = RequestMethod.POST)
public String addSatisfaction(#PathVariable int tokenId, #Valid ReceiptForm receiptForm, BindingResult result, Model model) {
try {
for (SatisfactionForm satisfactionForm : receiptForm.getFeedbacks()) {
Feedback feedback = new Feedback();
feedback.setId(satisfactionForm.getFeedbackId());
Feedback feedback1 = heart2heartService.getFeedbackById(feedback);
Resolution resolution = new Resolution();
resolution.setId(feedback1.getReceipt().getResolutions().get(0).getId());
resolution.setSatisfactionLevel(satisfactionForm.getSatisfaction().name());
resolution.setComment(satisfactionForm.getComment());
heart2heartService.addSatisfaction(resolution);
model.addAttribute("success", "Satisfaction added for tokenId " + tokenId);
}
} catch (Exception e) {
logger.error("Exception :: ", e);
}
return "success2";
}
#RequestMapping(value = "/{tokenId}/", method = RequestMethod.GET)
public String getSatisfaction(#PathVariable int tokenId, Model model) {
Token token = new Token();
token.setId(tokenId);
try {
model.addAttribute("feedbacks", heart2heartService.getFeedbacksByToken(token));
} catch (Exception e) {
logger.error("Exception :: ", e);
}
return "heart2heart/closeFeedback";
}
My forms are:
public class ReceiptForm {
private List<SatisfactionForm> feedbacks = new ArrayList<SatisfactionForm>();
public List<SatisfactionForm> getFeedbacks() {
return feedbacks;
}
public void setFeedbacks(List<SatisfactionForm> feedbacks) {
this.feedbacks = feedbacks;
}
}
and
public class SatisfactionForm {
public static enum Satisfaction {
NOT_SATISFIED, SATISFIED
}
private String comment;
private int feedbackId;
private Satisfaction satisfaction;
public String getComment() {
return comment;
}
public int getFeedbackId() {
return feedbackId;
}
public Satisfaction getSatisfaction() {
return satisfaction;
}
public void setComment(String comment) {
this.comment = comment;
}
public void setFeedbackId(int feedbackId) {
this.feedbackId = feedbackId;
}
public void setSatisfaction(Satisfaction satisfaction) {
this.satisfaction = satisfaction;
}
}
I am getting the following error:
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'feedbacks[0]' available as request attribute
How do I fix this?
You did not specify the form-backing bean in your Thymeleaf template.
You are using the *{} operator to access fields of the bean, but Thymeleaf does not know
which bean you want to use. To resolve the error, add a th:object to your form.
Assuming that heart2heartService.getFeedbacksByToken(token) returns a ReceiptForm your form would look like this:
<form action="#" th:action="#{/heart2heart/token/__${tokenId}__/}" method="post" th:object="${feedbacks}">
I have a problem when trying to access the controller.
Here is my controller:
#Controller
#RequestMapping("/index.htm")
public class LoginController {
#Autowired
private UserService userService;
#RequestMapping(method = RequestMethod.GET)
public String showForm(Map model) {
model.put("index", new LoginForm());
return "index";
}
#RequestMapping(method = RequestMethod.POST)
public String processForm(LoginForm loginForm, BindingResult result,
Map model) {
if (result.hasErrors()) {
HashMap<String, String> errors = new HashMap<String, String>();
for (FieldError error : result.getFieldErrors()) {
errors.put(error.getField(), error.getDefaultMessage());
}
model.put("errors", errors);
return "index";
}
List<User> users = userService.getUsers();
loginForm = (LoginForm) model.get("loginForm");
for (User user : users) {
if (!loginForm.getEmail().equals(user.getEmail()) || !loginForm.getPassword().equals(user.getPassword())) {
return "index";
}
}
model.put("index", loginForm);
return "loginsuccess";
}
}
Here is my form:
<form:form action="index.htm" commandName="index">
<table border="0" cellspacing="12">
<tr>
<td>
<spring:message code="application.loginForm.email"/>
</td>
<td>
<form:input path="email"/>
</td>
<td class="error">
<form:errors path="email"/>
</td>
</tr>
<tr>
<td>
<spring:message code="application.loginForm.password"/>
</td>
<td>
<form:password path="password"/>
</td>
<td class="error">
<form:errors path="password"/>
</td>
</tr>
<tr>
<td>
<input type="submit" value="Submit"/>
</td>
</tr>
</table>
</form:form>
On form submit I am getting this exception:
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'index' available as request attribute.
What am I doing wrong here?
It's because you're only doing this bit down at the bottom
model.put("index", loginForm);
If you return from the validation error, or from a success, there is no backing object in the model map named "index" so your form tag that has commandName="index" pitches a fit.
A common solution is to simply do this
#ModelAttribute("index")
public LoginForm getLoginForm() {
return new LoginForm();
}
Then there will always be one present, and you can take adding it out of the GET method.