How to get model map from model by key variable thymeleaf - java

> java controller code
import com.springboot.app.controllers.GlobalController;
import com.springboot.app.entities.Branch;
import com.springboot.app.services.ReportParamsAccessListService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import javax.persistence.Tuple;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
#Controller
public class GlobalReportController extends GlobalController {
#Autowired
ReportParamsAccessListService reportParamsAccessListService;
protected String branchParam(Model model,String paramName,String type, String name){
ModelMap modelMap = new ModelMap();
List<Branch> branchList = branchService.findAll();
modelMap.put("branchList",branchList);
modelMap.put("attr_name",name);
modelMap.put("attr_type",type);
model.addAttribute("branch",modelMap);
return "branch_param";
}
protected String dateParam(Model model,String paramName,String type,String name){
ModelMap modelMap = new ModelMap();
modelMap.put("attr_name",name);
modelMap.put("attr_type",type);
model.addAttribute("date",modelMap);
return "date_param";
}
#RequestMapping(value = "/report/test",method = RequestMethod.GET)
public String reportParams(Model model,String reportLink) {
LinkedHashMap<String,String> params = new LinkedHashMap<String, String>();
List<Tuple> reportParamAccess = reportParamsAccessListService.getReportParamAccess("reports/remittance_rub");
for (int i = 0; i<reportParamAccess.size(); i++){
try {
String name = reportParamAccess.get(i).get("name").toString();
String paramName = reportParamAccess.get(i).get("param_name").toString();
String attrType = reportParamAccess.get(i).get("attr_type").toString();
String attrName = reportParamAccess.get(i).get("attr_name").toString();
switch (name){
case "branch":
params.put(paramName,branchParam(model,paramName,attrType,attrName));
break;
case "date":
params.put(paramName,dateParam(model,paramName,attrType,attrName));
default:
}
} catch (Exception e) {
e.printStackTrace();
}
}
//System.out.println("params = " + params);
model.addAttribute("params",params);
//System.out.println(" dataAlling = " + model);
//return "report_params";
return pageContent(model,"report_params");
}
}
> useing thymealeaf template engine
> html code template brach param fragment
<div class="col-3" xmlns:th="http://www.thymeleaf.org" th:fragment="branch_param">
<div class="form-group" >
<button type="button" id="dropdownUl" class="btn btn-info dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Select Branch
</button>
<div class="dropdown hide">
<ul>
<li th:each="branchList : ${branch.branchList}">
<input th:id = "'md_checkbox_' + ${branchList.id}" th:type="${branch.attr_type}" th:value="${branchList.ip}" th:name="${branch.attr_name}" class="filled-in chk-col-light-blue" />
<label th:for="'md_checkbox_' + ${branchList.id}" th:text="${branchList.name}"></label>
</li>
</ul>
</div>
</div>
</div>
> html code template report params fragment
<ul xmlns:th="http://www.thymeleaf.org" th:fragment="report_params">
<li th:each="paramEntry : ${params}">
<div th:include="${paramEntry.value} :: ${paramEntry.value}" th:with="ParamName=${paramEntry.key}">
</div>
</li>
</ul>
> html code template date params fragment
<div class="col-2" xmlns:th="http://www.thymeleaf.org" th:fragment="date_param">
<div class="form-group" >
<input th:type="${date.attr_type}" th:name="${date.attr_name}" class="form-control" />
</div>
</div>
I want pass variable ParamName from report params to branch param and date param then use ParamName in fragments
for example like this in branch param
<div class="col-3" xmlns:th="http://www.thymeleaf.org" th:fragment="branch_param">
<div class="form-group" >
<button type="button" id="dropdownUl" class="btn btn-info dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Select Branch
</button>
<div class="dropdown hide">
<ul>
<li th:each="branchList : ${ParamName.branchList}">
<input th:id = "'md_checkbox_' + ${branchList.id}" th:type="${branch.attr_type}" th:value="${branchList.ip}" th:name="${branch.attr_name}" class="filled-in chk-col-light-blue" />
<label th:for="'md_checkbox_' + ${branchList.id}" th:text="${branchList.name}"></label>
</li>
</ul>
</div>
</div>
</div>

This is done by preprocessing mechanism in Thymeleaf
Here is a snippet of what you want to do:
<li th:each="branchList : ${__${paramName}__.branchList}">

Related

Why javax validation not working in DTO class?

I am trying to learn the spring boot. And, I am stuck on the form validation process. I have followed the process as instructed here.
Here is my controller class
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
#Controller
public class TalentCategoryController {
#GetMapping("talent-category")
public ModelAndView create(CreateTalentCategoryRequest talentCategory) {
ModelAndView model = new ModelAndView();
model.setViewName("talent-category/create");
model.addObject("talentCategory", talentCategory);
return model ;
}
#Autowired
TalentCategoryService talentCategoryService ;
#RequestMapping(path="talent-category", method = RequestMethod.POST, consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
public ModelAndView store(#Valid #ModelAttribute CreateTalentCategoryRequest talentCategory, BindingResult result) {
// result.hasErrors is false
if(result.hasErrors()) {
System.out.println("Validation working");
ModelAndView model = new ModelAndView();
model.setViewName("talent-category/create");
return model;
}
System.out.println("Validation not working");
talentCategoryService.store();
return null ;
}
}
DTO class :
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import lombok.Data;
#Data
public class CreateTalentCategoryRequest {
#NotBlank(message="Cannot be empty")
#Size(min=10, max=30)
private String name ;
#NotBlank(message="Cannot be empty")
private String status ;
#NotBlank(message="Cannot be empty")
private String approved ;
#NotBlank(message="Cannot be empty")
private String sort_order ;
}
View :
<form th:object="${talentCategory}" name="create-talent-category" method="POST" th:action="#{/talent-category}">
<div class="row">
<div class="col-4">
<div class="form-group">
<label for="name">Name</label>
<input th:field="*{name}" type="text" class="form-control form-control-sm" id="name" placeholder="Category Name" />
<p class="alert alert-danger" th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></p>
</div>
</div>
<div class="col-2">
<div class="form-group">
<label for="sort_order">Sort Order</label>
<input type="text" class="form-control form-control-sm" id="sort_order" placeholder="Eg : 1" />
</div>
</div>
<div class="col-2">
<div class="form-group">
<label for="status">Status</label>
<select name="status" id="status" class="form-control form-control-sm">
<option selected>Choose...</option>
<option value="1">Active</option>
<option value="0">Passive</option>
</select>
</div>
</div>
<div class="col-2">
<div class="form-group">
<label for="approved">Approved</label>
<select name="approved" id="approved" class="form-control form-control-sm">
<option selected>Choose...</option>
<option value="1">Yes</option>
<option value="0">No</option>
</select>
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<button name="create" class="btn btn-sm btn-primary">Create</button>
</div>
</div>
</form>
When a form is submitted with all the fields empty, the request is not redirect to the form(prints validation not working in console).
if you are using spring version 2.3+ , make sure you have following dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

Java +springboot +mysql search doesnt work

import com.example.news.models.Posting;
import org.springframework.data.repository.CrudRepository;
import java.util.List;
public interface PostRepos extends CrudRepository<Posting, Long> {
List<Posting> findByTag(String tag);
}
_____________________________________________________________________________
#PostMapping("find")
public String find(#RequestParam String find, Map<String, Object> model){
Iterable<Posting> posts;
if(find != null && find.isEmpty()) {
posts = postRepos.findByTag(find);
} else {
posts = postRepos.findAll();
}
model.put("posts",posts);
return "redirect:/newspage";
}
______________________________________________________________________________
<div th:fragment="head" xmlns:th="http://www.w3.org/1999/xhtml">
<div class="d-flex flex-column flex-md-row align-items-center p-3 px-md-4 mb-3 bg-white border-bottom shadow-sm">
<h5 class="my-0 mr-md-auto font-weight-normal">ASAP NEWS</h5>
<nav class="my-2 my-md-0 mr-md-3">
<a class="p-2 text-dark" href="/homepage">Main page</a>
<a class="p-2 text-dark" href="/newspage">News</a>
<a class="p-2 text-dark" href="/newspage/addpage">Add news</a>
<a class="p-2 text-dark" href="/aboutpage">About</a>
</nav>
<a>
<form method="post" action="find">
<label>
<input type="text" placeholder="Search" name="find">
</label>
<button type="submit">Find</button>
</form>
</a>
</div>
</div>
it seems a missed ! mark before find.isEmpty()

Java : Cannot send a form with Angular 5 that contain an input of type file to a REST backend (Spring Boot)

i am working in a project in school, backend is a REST based on Spring Boot, Frontend is an Angular 5 application. i have red a lot of tutorials but i cannot
find the right answer for my question:
-How can i post a form that contain an input of type file and others input of type text
-i want to send a form that contain a picture to backend, after that i want to take the file, rename it with unique name and upload it to a folder and put the URL in the DataBase
-i Have this Error in Backend :
Unexpected character ('-' (code 45)) in numeric value: expected digit (0-9) to follow minus sign, for valid numeric value
Here is the Entity:
#Entity
public class Prestataires implements Serializable {
#Id #GeneratedValue
private Long id;
private String nom;
private String email;
private String tele;
private String fax;
private String rib;
private String adresse;
private String taches;
private String photo;
private File file;
//-------------------Constructors--------------------
//-------------------Getters and Setters-------------
}
Here is the RestController Class :
package smart.syndic.web;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import smart.syndic.dao.PrestatairesRepository;
import smart.syndic.entities.Prestataires;
#RestController
#CrossOrigin("*")
public class PrestatairesRestController {
#Autowired
private PrestatairesRepository repository;
#RequestMapping(value="/prestataires",
method=RequestMethod.POST)
public Prestataires addPrestataires(
#RequestBody Prestataires v) {
/*
Here will be the code to process the file coming from front End and
uploading it to folder then put the URL to DataBase
*/
return repository.save(v);
}
}
Here is the front end App:
<form class="form-horizontal form-label-left" #f1="ngForm">
<div id="containerAjouterPrestataires">
</div>
<div class="form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12">Raison Social/Nom<span class="required">*</span>
</label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input [(ngModel)]="nom" name="nom" type="text" required class="form-control col-md-7 col-xs-12">
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12">Email<span class="required">*</span>
</label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input [(ngModel)]="email" name="email" type="email" required class="form-control col-md-7 col-xs-12">
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12">Téléphone<span class="required">*</span></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input [(ngModel)]="tele" name="tele" class="form-control col-md-7 col-xs-12" type="text" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12">Fax<span class="required">*</span></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input [(ngModel)]="fax" name="fax" class="form-control col-md-7 col-xs-12" type="text" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12">RIB<span class="required">*</span></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input [(ngModel)]="rib" name="rib" class="form-control col-md-7 col-xs-12" type="text" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12">Type<span class="required">*</span></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<div class="input-group">
<select class="form-control" name="selectTypes" [(ngModel)]="selectTypes">
<option selected="selected" *ngFor="let s of tousLesPrestatairesTypes" [value]="s.id" >
{{s.designation}}
</option>
</select>
<span class="input-group-btn">
<!-- Button trigger modal -->
<button type="button" class="btn btn-default" data-toggle="modal" data-target="#myModal">
Ajouter Type
</button>
</span>
</div>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12">Adresse<span class="required">*</span>
</label>
<div class="col-md-6 col-sm-6 col-xs-12">
<textarea [(ngModel)]="adresse" name="adresse" class="form-control" rows="3" placeholder="Adresse"></textarea>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12">Tâches<span class="required">*</span>
</label>
<div class="col-md-6 col-sm-6 col-xs-12">
<textarea [(ngModel)]="taches" name="taches" class="form-control" rows="3" placeholder="Tâches"></textarea>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12">Photo/Logo<span class="required">*</span></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input name="photo" class="form-control col-md-7 col-xs-12"
type="file" required="required" accept="image/*"
(change)="handleFileInput($event)">
</div>
</div>
<div class="form-group">
<div class="col-md-6 col-sm-6 col-xs-12 col-md-offset-3">
<button class="btn btn-warning" type="reset">Vider</button>
<button type="button" class="btn btn-success" (click)="ajouterPrestataires()">Ajouter</button>
</div>
</div>
</form>
Here is the TypeScript Controller:
import { Component, OnInit } from '#angular/core';
import {PrestatairesService} from "../../services/prestataires.service";
import {PrestatairesTypeModel} from "../../modeles/prestatairesType.model";
import {PrestatairesModel} from "../../modeles/prestataires.model";
#Component({
selector: 'app-ajouter-prestataires',
templateUrl: './ajouter-prestataires.component.html',
styleUrls: ['./ajouter-prestataires.component.css']
})
export class AjouterPrestatairesComponent implements OnInit {
nom:any;
email:any;
tele:any;
fax:any;
rib:any;
adresse:any;
taches:any;
photo:any;
selectTypes:any;
typePrestataire:any;
tousLesPrestatairesTypes:any;
modelType:any;
imageURL:string = "../assets/images/MeG.jpg";
fileToUpload:File = null;
modelPrestataires:any;
constructor(private service:PrestatairesService) { }
ngOnInit()
{
this.getAllTypes();
}
handleFileInput(file:any)
{
this.fileToUpload = <File>file.target.files[0];
}
ajouterPrestataires()
{
this.modelPrestataires = new PrestatairesModel();
this.modelPrestataires.nom = this.nom;
this.modelPrestataires.email = this.email;
this.modelPrestataires.tele = this.tele;
this.modelPrestataires.fax = this.fax;
this.modelPrestataires.rib = this.rib;
this.modelPrestataires.adresse = this.adresse;
this.modelPrestataires.taches = this.taches;
this.modelPrestataires.file = this.fileToUpload;
this.modelPrestataires.photo = this.photo;
this.getOneType(this.selectTypes);
this.modelPrestataires.prestatairesTypes = this.modelType;
this.service.uploadFile(this.modelPrestataires)
.subscribe(data=>{
console.log("Success");
}, err=>{
console.log("Error");
}, ()=>{
});
}
Here is the service :
import {Injectable} from "#angular/core";
import {HttpClient, HttpEvent, HttpHeaders, HttpParams, HttpRequest} from
"#angular/common/http";
#Injectable()
export class PrestatairesService
{
host:string = "http://localhost:8080/";
constructor(private http:HttpClient)
{
}
uploadFile(model:any){
let formData = new FormData();
formData.append('fichier', model.file);
let headers = new HttpHeaders().set('Content-Type','application/json');
let params = new HttpParams();
const options = {
params: params,
reportProgress: true,
headers: headers
};
const req = new HttpRequest('POST', this.host + "prestataires", formData,
options);
return this.http.request(req);
}
}
When uploading the file to the backend you can use Multipart file. You could also Base64 encode the file in the frontend and send it as a JSON string, but that causes a lot more bytes being sent over the wire.
In the multipart solution your controller should expect a multipart file like so.
Controller
#RestController
#CrossOrigin("*")
public class PrestatairesRestController {
#Autowired
private PrestatairesRepository repository;
#RequestMapping(value="/prestataires", method=RequestMethod.POST)
// you don't have to add #RequestBody for the Prestataires
public String postFileUpload(Prestataires prestataires, #RequestParam("multipartFile") MultipartFile file) {
// Make sure that in the frontend the name of the form field for the file is also multipartFile
// Also make sure that the mime type in the frontend is multipart/form-data
byte[] rawFile;
try {
rawFile = file.getBytes();
} catch (IOException e) {
e.printStackTrace();
return "error?";
}
prestataires.setFile(rawFile);
prestatairesRepository.save(prestataires);
return "redirect:/ or send response";
}
}
Your entity can't just have a File class as field. You need to have a byte[]; you will ultimately be storing raw bytes in your database - I think other datatypes are also allowed.
Entity
#Entity
public class Prestataires implements Serializable {
#Id #GeneratedValue
private Long id;
private String nom;
private String email;
private String tele;
private String fax;
private String rib;
private String adresse;
private String taches;
private String photo;
#Lob
#Column(name = "file", columnDefinition="BLOB")
private byte[] file;
//-------------------Constructors--------------------
//-------------------Getters and Setters-------------
}
For the Angular part I suppose this is a perfect example of what you need to upload files: https://stackoverflow.com/a/40216616/5473627

Null parameters when sending post to Spring Controller

I've been trying to solve this issue for a lot of time but I can't see what is wrong in my configuration.
The thing I'm trying to do is to create a new "Metadata" object. This object has the following domain class:
package domain;
import java.util.ArrayList;
import java.util.Collection;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Entity;
import javax.persistence.ManyToMany;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import org.codehaus.jackson.annotate.JsonIgnore;
import org.hibernate.validator.constraints.NotBlank;
#Entity
#Access(AccessType.PROPERTY)
public class Metadata extends DomainEntity{
private String name;
//Relationship
private Collection<Question> questions;
public Metadata() {
super();
questions = new ArrayList<Question>();
}
#Valid
#NotBlank
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Valid
#NotNull
#ManyToMany(mappedBy = "metadata")
public Collection<Question> getQuestions() {
return questions;
}
public void setQuestions(Collection<Question> questions) {
this.questions = questions;
}
}
So I have a button that goes to a create page with empty input of property "name" (rest of properties are empty or autogenerated by spring). The view for the creation is the following:
<%#page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%#taglib prefix="jstl" uri="http://java.sun.com/jsp/jstl/core"%>
<%#taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%#taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%#taglib prefix="security"
uri="http://www.springframework.org/security/tags"%>
<%#taglib prefix="display" uri="http://displaytag.sf.net"%>
<%# taglib prefix="acme" tagdir="/WEB-INF/tags"%>
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="well well-sm">
<form:form class="form-horizontal" method="POST"
action="metadata/edit.do" modelAttribute="metadata"
enctype="multipart/form-data">
<form:hidden path="id" />
<form:hidden path="version" />
<form:hidden path="questions" />
<fieldset>
<!-- Name -->
<div class="form-group">
<form:label path="name" class="col-md-3 control-label" for="name">
<spring:message code="metadata.name" />
</form:label>
<div class="col-md-6">
<form:input path="name" id="name" name="name" type="text"
class="form-control" />
</div>
<form:errors path="name" cssClass="error" />
</div>
<!-- Form actions -->
<div class="form-group">
<div class="col-md-12 text-center">
<input type="submit" name="save" class="btn btn-primary btn-lg"
value="<spring:message code="metadata.save" />" />
<%-- <jstl:if test="${!create}"> --%>
<!-- <a class="btn btn-primary btn-lg" data-toggle="modal" -->
<%-- data-target="#basicModal"><spring:message --%>
<%-- code="metadata.delete" /></a> --%>
<!-- <div class="modal fade" id="basicModal" tabindex="-1" -->
<!-- role="dialog" aria-labelledby="basicModal" aria-hidden="true"> -->
<!-- <div class="modal-dialog"> -->
<!-- <div class="modal-content"> -->
<!-- <div class="modal-header"> -->
<!-- <button type="button" class="close" data-dismiss="modal" -->
<!-- aria-hidden="true">×</button> -->
<!-- <h4 class="modal-title" id="myModalLabel"> -->
<%-- <spring:message code="metadata.confirm.title" /> --%>
<!-- </h4> -->
<!-- </div> -->
<!-- <div class="modal-body"> -->
<!-- <h3> -->
<%-- <spring:message code="metadata.confirm.body" /> --%>
<!-- </h3> -->
<!-- </div> -->
<!-- <div class="modal-footer"> -->
<!-- <button type="submit" name="delete" class="btn btn-default" -->
<!-- onclick="history.back()"> -->
<%-- <spring:message code="metadata.confirm.yes" /> --%>
<!-- </button> -->
<!-- <button type="button" class="btn btn-primary" -->
<!-- data-dismiss="modal"> -->
<%-- <spring:message code="metadata.confirm.no" /> --%>
<!-- </button> -->
<!-- </div> -->
<!-- </div> -->
<!-- </div> -->
<!-- </div> -->
<%-- </jstl:if> --%>
<a href="metadata/list.do"><input type="button"
class="btn btn-primary btn-lg"
value="<spring:message code="metadata.cancel"/>" id="cancelar"
name="cancelar"
onclick="self.location.href = metadata/list.do" /></a>
</div>
</div>
</fieldset>
</form:form>
</div>
</div>
</div>
</div>
And finally, my controller class, which is failing due to BindingProvider has errors because property "name" of Metadata object cannot be null:
package controllers;
import java.util.ArrayList;
import java.util.Collection;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import services.MetadataService;
import domain.Metadata;
import domain.Question;
#Controller
#RequestMapping("/metadata")
public class MetadataController {
// Services ----------------------------------------------------------------
#Autowired
private MetadataService metadataService;
// Constructor
// ---------------------------------------------------------------
public MetadataController() {
super();
}
// Listing
// -------------------------------------------------------------------
#RequestMapping("/list")
public ModelAndView list() {
ModelAndView result;
String uri = "metadata/list";
String requestURI = "metadata/list.do";
Collection<Metadata> metadatas = metadataService.findAll();
result = createListModelAndView(requestURI, metadatas, uri);
return result;
}
// Creation
// ------------------------------------------------------------------
#RequestMapping(value = "/create", method = RequestMethod.GET)
public ModelAndView create() {
ModelAndView result;
Metadata metadata = metadataService.create();
result = createCreateModelAndView(metadata);
return result;
}
// Edition
// -------------------------------------------------------------------
#RequestMapping(value = "/edit", method = RequestMethod.GET)
public ModelAndView edit(#RequestParam int metadataId) {
ModelAndView result;
Metadata metadata = metadataService.findOne(metadataId);
result = createEditModelAndView(metadata);
return result;
}
#RequestMapping(value = "/edit", method = RequestMethod.POST)
public ModelAndView save(#Valid Metadata metadata, BindingResult binding,
RedirectAttributes redirect) {
ModelAndView result;
if (binding.hasErrors()) {
if (metadata.getId() == 0) {
result = createEditModelAndView(metadata, "metadata.commit.error");
} else {
result = createCreateModelAndView(metadata, "metadata.commit.error");
}
} else {
try {
metadataService.save(metadata);
result = new ModelAndView("redirect:list.do");
} catch (Throwable oops) {
if (metadata.getId() == 0) {
result = createEditModelAndView(metadata, "metadata.commit.error");
} else {
result = createCreateModelAndView(metadata, "metadata.commit.error");
}
}
}
return result;
}
// #RequestMapping(value = "/edit", method = RequestMethod.POST, params = "delete")
// public ModelAndView delete(#ModelAttribute Metadata metadata,
// BindingResult bindingResult, RedirectAttributes redirect) {
// ModelAndView result;
//
// try {
// redirect.addFlashAttribute("successMessage", "metadata.deleteSuccess");
// metadataService.delete(metadata);
// result = new ModelAndView("redirect:list.do");
// } catch (Throwable oops) {
// if (oops.getMessage() == "Error") {
// result = createEditModelAndView(metadata, "metadata.error");
// } else {
// result = createEditModelAndView(metadata, "metadata.commit.error");
// }
// }
// return result;
// }
// Other bussiness method
protected ModelAndView createEditModelAndView(Metadata metadata) {
assert metadata != null;
ModelAndView result;
result = createEditModelAndView(metadata, null);
return result;
}
protected ModelAndView createCreateModelAndView(Metadata metadata) {
assert metadata != null;
ModelAndView result;
result = createCreateModelAndView(metadata, null);
return result;
}
protected ModelAndView createEditModelAndView(Metadata metadata,
String message) {
assert metadata != null;
Collection<Question> questions = new ArrayList<Question>();
ModelAndView result;
result = new ModelAndView("metadata/edit");
result.addObject("questions", questions);
result.addObject("metadata", metadata);
return result;
}
protected ModelAndView createCreateModelAndView(Metadata metadata,
String message) {
assert metadata != null;
Collection<Question> questions = new ArrayList<Question>();
ModelAndView result;
result = new ModelAndView("metadata/create");
result.addObject("questions", questions);
result.addObject("create", true);
result.addObject("metadata", metadata);
return result;
}
protected ModelAndView createListModelAndView(String requestURI,
Collection<Metadata> metadatas, String uri) {
ModelAndView result;
result = new ModelAndView(uri);
result.addObject("metadatas", metadatas);
result.addObject("requestURI", requestURI);
return result;
}
}
After looking at this for days, I can not make the submit button to send the values I want to the controller and I don't know what to do. There is no log errors. It just returns to the creation page saying that "name" cannot be null.
public ModelAndView save(#Valid Metadata metadata
i think you are missing #ModelAttribute annotation in the abovve line. you can use it as a
parameter when you want to bind data from the request and add it to the model implicitly.
so change your save method to
public ModelAndView save(#ModelAttribute("metadata") #Valid Metadata metadata
this should work and appereciate if you could post the result.
The problem was that I was using enctype=multipart... while I was not sending any binary data.
That seemed to generate some conflicts in Spring. Removing that enctype and letting Spring use the default setting for it solved the problem.

JSF page ends in a redirect loop

My browser is always returning a redirect loop and I have no idea why, it looks like when I access login.html it is calling some of my methods.
Here is the login.html file:
<ui:composition
template="/templates/master.xhtml"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html">
<ui:define name="body">
<div class="container-fluid">
<div class="row-fluid">
<div class="span12">
<h:form class="form-horizontal">
<fieldset>
<legend>Bem vindo a Sergio's</legend>
<br/>
<p>Preencha os campos abaixo para entrar no sistema.</p>
<div class="control-group">
<label class="control-label" for="user">Usuário</label>
<div class="controls">
<h:inputText required="true" id="user" value="#{loginController.username}" class="input-medium" />
<h:message for="user" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="password">Senha</label>
<div class="controls">
<h:inputSecret required="true" id="password" value="#{loginController.password}" class="input-medium"/>
<h:message for="password" />
</div>
</div>
<div class="form-actions">
<h:commandButton action="#{loginController.login()}" class="btn btn-primary" value="Entrar"/>
</div>
</fieldset>
</h:form>
<h:messages/>
</div>
</div>
</div>
</ui:define>
</ui:composition>
And here is the LoginController:
package com.erp3.gui.controllers;
import java.io.IOException;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
#ManagedBean
public class LoginController {
public Boolean isLoggedIn = false;
private String username;
private String password;
private FacesMessage facesMessage;
public ExternalContext externalContent;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Boolean getIsLoggedIn() {
return isLoggedIn;
}
public void setIsLoggedIn(Boolean isLoggedIn) {
this.isLoggedIn = isLoggedIn;
}
public void login() throws IOException {
if (this.getUsername().equals("daniel") && this.getPassword().equals("123")) {
this.isLoggedIn = true;
externalContent = FacesContext.getCurrentInstance().getExternalContext();
externalContent.getSessionMap().put("loginController", this);
externalContent.redirect(externalContent.getRequestContextPath() + "/views/home.html");
} else {
this.isLoggedIn = false;
facesMessage = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Usuário ou senha inválida.", username);
FacesContext.getCurrentInstance().addMessage(null, facesMessage);
externalContent.redirect(externalContent.getRequestContextPath() + "/views/login.htm");
}
}
public void logOut() throws IOException {
externalContent = FacesContext.getCurrentInstance().getExternalContext();
externalContent.getSessionMap().remove("loginController");
externalContent.redirect(externalContent.getRequestContextPath() + "/views/login.html");
}
}
I have a master.html that is my template and it is calling a top.html with this content:
<ui:composition
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container-fluid">
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<a class="brand" href="#">Project name</a>
<div class="btn-group pull-right">
<a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
<i class="icon-user"></i>
<span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li>Conta</li>
<li class="divider"></li>
<li>Sair</li>
</ul>
</div>
<div class="nav-collapse">
<ul class="nav">
<li class="active">Home</li>
<li>About</li>
<li>Contact</li>
</ul>
</div>
</div>
</div>
</div>
</ui:composition>
EL expressions in template text are immediately evaluated during render response and treated as value expressions. I.e. their return value is been printed as part of HTML output. "Plain vanilla" HTML is also template text. So the following
<li>Sair</li>
will basically invoke the method, print its returned value as href URL during render response. The resulting HTML is then:
<li>Sair</li>
(yes, the href is empty because you actually returned void instead of a valid String)
But inside that method you're telling JSF to redirect to the login page and hence it ends up in an infinite loop.
This is not what you actually want. You intend to invoke it as a backing bean action method. You should be using fullworthy JSF UICommand component for this, such as <h:commandLink>.
<li><h:form><h:commandLink value="Sair" action="#{loginController.logOut()}" /></h:form></li>
This way you can also change your logOut() method to return a fullworthy navigation outcome:
public String logOut() {
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
return "/views/login.html?faces-redirect=true";
}
The ExternalContext#redirect() is supposed to be used only when you want to redirect to a non-JSF URL, or when you're actually not inside an action method.
found the problem, on my top.html, I'm calling loginController.logOut() on a link and I don't know why it is auto executing, is not waiting for my click so I changed the <a> for <h:commandLink/>

Categories