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()
Related
I am working on a springboot+thymeleaf project. I have a page(form) which accepts user data (startdate and enddate),and a button(Check). On click of the button, backend does some validation. If there are errors, I print the errors on the textarea within the same page (below the check button). If there are no errors, then I activate another button below the textarea, to signify that the entries between the mentioned dates are ready to be stored in the database.
<!DOCTYPE html>
<html xmlns:th="https://www.thymeleaf.org"
xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<body>
<div th:fragment="contentinput">
<div class="container-md">
<a>Import Worklogs</a>
<div class="row justify-content-md-end">
<form modelAttribute = "userData">
<div class="row">
<div class="col-2">
<input type="text" class="form-control" id="txtFrom"
placeholder="start date(yyyy-mm-dd)" name="dateFrom">
</div>
<div class="col-2">
<input type="text" class="form-control" id="txtTo"
placeholder="end date(yyyy-mm-dd)" name="dateTo">
</div>
</div>
<div>
<br>
</div>
<div class="row">
<div class="row-2">
<input type="submit" class="btn btn-primary btn-sml"
value="check">
</div>
</div>
</form>
</div>
</div>
</div>
<div th:fragment="contentresult">
<div class="container-md">
<div class="row">
<div class="row">
<label style="color: black; font-weight: bold;">Issues: </label>
</div>
<br>
<div class="row">
<label for="Feedback"
th:text="'checking entries between '+ ${dateFrom}+' and '+ ${dateTo}"></label>
</div>
<div>
<textarea id="feedbackSection" name="story" cols="100" rows="10"
th:text="${styledErrors}">
</textarea>
</div>
</div>
<div>
<label th:if="${containsErrors}" style="color: green;"> There are
no issues. The entries can be imported</label>
<label
th:unless="${containsErrors}" style="color: red;"> There are
issues! Read the above for details</label>
</div>
<br>
<div class="row">
<div class="row-2">
<a th:if="${containsErrors}" type="button" th:attr="href='/importToDb'"
class="btn btn-primary btn-sml">Import</a>
<input th:unless="${containsErrors}" type="button" disabled="disabled"
value="Import">
</div>
</div>
</div>
</div>
<div th:fragment="contentmessage">
<div class="container-md">
<div class="row">
<label style="color: green; font-weight: bold;"
th:text="'Entries between '+ ${dateFrom}+' and '+ ${dateTo}+' are stored on the database'"></label>
</div>
</div>
</div>
</body>
</html>
I have run into a problem in my controller application for the import button. When I click on the import, I want to utilise the features that were used while clicking the button (check)
#GetMapping("/showform")
public String showForm(#RequestParam(value = "dateFrom", required = false) String dateFrom,
#RequestParam(value = "dateTo", required = false) String dateTo, Model model)
throws IOException, JSONException, InterruptedException, ExecutionException,
NumberFormatException, SQLException {
if (dateFrom != null && dateTo != null && !dateFrom.isBlank() && !dateTo.isBlank()) {
logger.info("inside the datefrom dateto");
CheckManager wm = prepareConfiguration(dateFrom, dateTo);
model.addAttribute("containsErrors", wm.getErrors().isEmpty());
model.addAttribute("styledErros", wm.getFormattedErrors(wm.getErrors()));
model.addAttribute("dateFrom", dateFrom);
model.addAttribute("dateTo", dateTo);
return "showform-errors"; //shows the fragment with contentinput and contentResult
} else {
logger.info("inside the validationform");
return "showform"; //only contentinput( having 2 textboxes for dates and a button)
}
}
private CheckManager prepareConfiguration(String dateFrom, String dateTo)
throws IOException, JSONException, InterruptedException, ExecutionException,
NumberFormatException, SQLException {
LocalDate from = LocalDate.parse(dateFrom, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
LocalDate to = LocalDate.parse(dateTo, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
Request req = new Request("username", "password");
List<Entry> entrylist = req.getEntryList(from,to);
// I want this info entrylist to be used globally
return new CheckManager(entryList,from,to);
}
#GetMapping("/placeinDB")
public String placeInDb(Model model) {
logger.info("Inside the db import");
//HERE I WOULD LIKE TO USE THE DATES AND THE LIST I HAD IN THE ABOVE RETURN STATEMENT
}
Problem: When I hit the endpoint(/placeinDB) I do not have the resources like entryList, datefrom, dateTo to perform some modifications.
I am hoping there is some spring annotation that could help me here. Please let me know.
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
I have a Status Code 400in the frontend when i try to send a POST request with Angular 5 to Spring Boot Rest Controller.
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;
#Lob
private byte[] file;
#ManyToOne
#JoinColumn(name="ID_PRESTATAIRES_TYPES")
private PrestatairesTypes prestatairesTypes;
//--------------Getters and Setters------------------------
//--------------Constructors-------------------------------
}
Here is the Second Entity:
#Entity
public class PrestatairesTypes implements Serializable
{
#Id #GeneratedValue
private Long id;
private String designation;
//-------------------Constructors----------------
//--------------Getters and Setters-------------------
//---------------------OneToMany---------------------
#OneToMany(mappedBy="prestatairesTypes")
private Collection<Prestataires> prestataires;
}
Here is the RestController :
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 org.springframework.web.multipart.MultipartFile;
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 addVilles(Prestataires p,
#RequestParam("multipartFile") MultipartFile file)
{
byte[] rawFile = null;
try{
rawFile = file.getBytes();
}catch(Exception e){
e.printStackTrace();
}
p.setFile(rawFile);
return repository.save(p);
}
}
Here is The Model Prestataires in TypeScript :
export class PrestatairesModel
{
id:any;
nom:any;
email:any;
tele:any;
fax:any;
rib:any;
adresse:any;
taches:any;
photo:any;
file:any;
prestatairesTypes:any;
}
Here is the model PrestatairesTypes in TypeScript:
export class PrestatairesTypeModel
{
id:any;
designation:any;
}
Here is the Angular Controller in TypeScript :
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 = null;
email:any = null;
tele:any = null;
fax:any = null;
rib:any = null;
adresse:any = null;
taches:any = null;
photo:any = null;
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];
let reader = new FileReader();
reader.onload = (event:any)=>{
this.imageURL = event.target.result;
}
reader.readAsDataURL(this.fileToUpload);
}
getAllTypes()
{
this.service.getAllTypes()
.subscribe(data=>{
this.tousLesPrestatairesTypes = data;
}, err=>{
}, ()=>{
})
}
ajouterTypesPrestataires()
{
this.modelType = new PrestatairesTypeModel();
this.modelType.designation = this.typePrestataire;
this.service.ajouterType(this.modelType)
.subscribe(data=>{
console.log("Added");
this.getAllTypes();
this.modelType = data;
}, err=>{
console.log("Error");
}, ()=>{
})
}
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.photo = this.photo;
this.modelPrestataires.file = this.fileToUpload;
this.service.getOneType(this.selectTypes)
.subscribe(data=>{
this.modelPrestataires.prestatairesTypes = data;
}, err=>{
}, ()=>{
this.service.uploadFile(this.modelPrestataires)
.subscribe(data=>{
this.modelPrestataires = data;
}, err=>{
}, ()=>{
});
});
}
getOneType(id:any)
{
this.service.getOneType(id)
.subscribe(data=>{
this.modelType = data;
}, err=>{
}, ()=>{
});
}
}
Here is the View :
<div class="right_col" role="main">
<div class="">
<div class="page-title">
<div class="title_left">
<h3>Ajouter Prestataires</h3>
</div>
</div>
<div class="clearfix"></div>
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="x_panel">
<div class="x_title">
<h2>Nouveau Prestataire</h2>
<ul class="nav navbar-right panel_toolbox">
<li><a class="collapse-link"><i class="fa fa-chevron-up"></i></a>
</li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown"
role="button" aria-expanded="false"><i class="fa fa-wrench"></i></a>
<ul class="dropdown-menu" role="menu">
<li><a routerLink="/prestataires">Retour Prestataires</a>
</li>
</ul>
</li>
<li><a class="close-link"><i class="fa fa-close"></i></a>
</li>
</ul>
<div class="clearfix"></div>
</div>
<div class="x_content">
<div class="x_content">
<div id="containerAjouterPrestataires">
</div>
<form class="form-horizontal form-label-left">
<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>
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1"
role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-
dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span>
</button>
<h4 class="modal-title" id="myModalLabel">Ajouter Type
Prestataire</h4>
</div>
<div class="modal-body">
<form class="form-horizontal form-label-left">
<div id="containerType">
</div>
<div class="form-group">
<label class="control-label col-md-3 col-sm-3 col-
xs-12">Nouveau Type<span class="required">*</span></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input [(ngModel)]="typePrestataire"
name="typePrestataire" class="form-control col-md-7 col-xs-12" type="text"
required>
</div>
<button type="button" class="btn btn-success"
(click)="ajouterTypesPrestataires()">Ajouter</button>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-
dismiss="modal" id="fermer">Fermer</button>
</div>
</div>
</div>
</div>
<!-- /modal -->
<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="multipartFile" class="form-control col-md-7
col-xs-12"
type="file" required="required"
(change)="handleFileInput($event)">
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-
12">Image Preview</label>
<div class="col-md-6 col-sm-6 col-xs-12">
<img class="imagePrestataires" [src]="imageURL">
</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>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
Here is the Service.ts
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)
{
}
getAllTypes()
{
return this.http.get(this.host + "prestatairesTypes");
}
ajouterType(model:any)
{
return this.http.post(this.host + "prestatairesTypes", model);
}
getOneType(id:any)
{
return this.http.get(this.host + "prestatairesTypes/" + id);
}
ajouterPrestataires(model:any)
{
return this.http.post(this.host + "prestataires", model);
}
uploadFile(model:any)
{
let formData = new FormData();
formData.append('multipartFile', model.file);
formData.append('nom', model.nom);
formData.append('email', model.email);
formData.append('rib', model.rib);
formData.append('taches', model.taches);
formData.append('fax', model.fax);
formData.append('adresse', model.adresse);
// This is the line that cause the Error of status code 400
// What to do here to send the request correctly
formData.append('prestatairesTypes', model.prestatairesTypes);
formData.append('tele', model.tele);
let params = new HttpParams();
const options = {
params: params,
reportProgress: true,
};
const req = new HttpRequest('POST', this.host+"prestataires", formData,
options);
return this.http.request(req);
}
}
If you set the file name to multipartFile, it should work.
The problem is that the #RequestParam("multipartFile") MultipartFile file isn't receiving the file, because there is no form field with the name multipartFile. That is what you configured with #RequestParam.
This is a postman snippet that you can use. Check the last parameter.
POST /prestataires HTTP/1.1
Host: localhost:8080
Cache-Control: no-cache
Postman-Token: 809c9cd4-8b66-43e6-939c-1f2a554ca982
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="nom"
NOM
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="email"
EMAIL
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="tele"
TELE
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="fax"
FAX
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="rib"
RIB
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="adresse"
ADRESSE
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="taches"
TACHES
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="photo"
PHOTO
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="multipartFile"; filename="demo.txt"
Content-Type: text/plain
------WebKitFormBoundary7MA4YWxkTrZu0gW--
I'm working on a Spring Boot + Bootstrap project.
I've created a modal window to confirm the removal of itens, but after I added Spring Security to the project, the modal stopped working.
How can I properly configure the CSRF token in a modal window?
I have tried some approaches, with no success.
I get the following error when deleting itens:
There was an unexpected error (type=Forbidden, status=403). Invalid
CSRF Token 'null' was found on the request parameter '_csrf' or header
'X-CSRF-TOKEN'.
Thanks for the help!
confirmRemove.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<div class="modal fade" id="confirmRemove" tabindex="-1"
data-keyboard="false" data-backdrop="static">
<div class="modal-dialog">
<form th:attr="data-url-base=#{/restaurants}" method="POST">
<input type="hidden" name="_method" value="DELETE" />
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">Você tem certeza?</h4>
</div>
<div class="modal-body">
<span>Are you sure you want to delete this restaurant?</span>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-link" data-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-primary">Delete</button>
</div>
</div>
</form>
</div>
</div>
</html>
restaurantpoll.js
$('#confirmRemove').on(
'show.bs.modal',
function(event) {
var button = $(event.relatedTarget);
var codeRestaurant = button.data('id');
var nameRestaurant = button.data('name');
var modal = $(this);
var form = modal.find('form');
var action = form.data('url-base');
if (!action.endsWith('/')) {
action += '/';
}
form.attr('action', action + codeRestaurant);
modal.find('.modal-body span').html(
'Are you sure you want to delete <strong>'
+ nameRestaurant + '</strong>?')
});
RestaurantController (only the relevant part)
package com.matmr.restaurantpoll.controller;
import java.util.Arrays;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.Errors;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import com.matmr.restaurantpoll.exception.RestaurantNotFoundException;
import com.matmr.restaurantpoll.model.Category;
import com.matmr.restaurantpoll.model.Restaurant;
import com.matmr.restaurantpoll.model.filter.RestaurantFilter;
import com.matmr.restaurantpoll.service.RestaurantService;
#Controller
#RequestMapping("/restaurants")
public class RestaurantController {
#Autowired
private RestaurantService restaurantService;
#Autowired
public RestaurantController(RestaurantService restaurantService) {
this.restaurantService = restaurantService;
}
#RequestMapping(value = "{id}", method = RequestMethod.DELETE)
public String delete(#PathVariable Long id, RedirectAttributes attributes) throws RestaurantNotFoundException {
restaurantService.deleteById(id);
attributes.addFlashAttribute("message", "The restaurant was successfully deleted.");
return "redirect:/restaurants";
}
}
restaurantList.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://ultraq.net.nz/thymeleaf/layout"
layout:decorator="Layout">
<head>
<title>Pesquisa de Restaurantes</title>
</head>
<section layout:fragment="conteudo">
<div class="panel panel-primary">
<div class="panel-heading">
<div class="clearfix">
<h1 class="panel-title liberty-title-panel">Pesquisa de
Restaurantes</h1>
<a class="btn btn-link liberty-link-panel"
th:href="#{/restaurants/new}">Cadastrar Novo Restaurante</a>
</div>
</div>
<div class="panel-body">
<form method="GET" class="form-horizontal"
th:action="#{/restaurants}" th:object="${filter}">
<div layout:include="MensagemGeral"></div>
<div layout:include="MensagemErro"></div>
<div class="form-group">
<div class="col-sm-4">
<div class="input-group">
<input class="form-control"
placeholder="Qual restaurante você está procurando?"
autofocus="autofocus" th:field="*{name}"></input> <span
class="input-group-btn">
<button type="submit" class="btn btn-default">
<i class="glyphicon glyphicon-search"></i>
</button>
</span>
</div>
</div>
</div>
</form>
<div class="table-responsive">
<table class="table table-bordered table-striped">
<thead>
<tr>
<th class="text-left col-md-1">#</th>
<th class="text-left col-md-2">Nome</th>
<th class="text-left col-md-3">Descrição</th>
<th class="text-left col-md-2">Categoria</th>
<th class="col-md-1"></th>
</tr>
</thead>
<tbody>
<tr th:each="restaurant : ${restaurants}">
<td class="text-left" th:text="${restaurant.id}"></td>
<td class="text-left" th:text="${restaurant.name}"></td>
<td class="text-left" th:text="${restaurant.description}"></td>
<td class="text-left"
th:text="${restaurant.category.description}"></td>
<td class="text-center"><a class="btn btn-link btn-xs"
th:href="#{/restaurants/{id}(id=${restaurant.id})}"
title="Editar" rel="tooltip" data-placement="top"> <span
class="glyphicon glyphicon-pencil"></span>
</a> <a class="btn btn-link btn-xs" data-toggle="modal"
data-target="#confirmRemove"
th:attr="data-id=${restaurant.id}, data-name=${restaurant.name}"
title="Excluir" rel="tooltip" data-placement="top"> <span
class="glyphicon glyphicon-remove"></span>
</a></td>
</tr>
<tr>
<td colspan="5" th:if="${#lists.isEmpty(restaurants)}">Nenhum
restaurante foi encontrado!</td>
</tr>
</tbody>
</table>
</div>
</div>
<div layout:include="confirmRemove"></div>
</div>
</section>
</html>
Adding th:action="#{/restaurants}" to the modal's form tag did the trick:
<form th:action="#{/restaurants}" th:attr="data-url-base=#{/restaurants}" method="POST">
I am using Spring MVC. I have a jsp page with multiple tabs. Each tab has a form. All these tabs are in a single jsp page called admin.jsp
I want to redirect the tab to itself upon POST to show errors or success message of transaction(Validation of input). What view should I return from the controller for each tab.
Controller:
#RequestMapping(value="/register", method = RequestMethod.POST)
public String registerDevice(#ModelAttribute("deviceMaster") #Validated DeviceMaster deviceMaster, BindingResult result, Model model, Locale locale) {
try {
if(result.hasErrors()){
return "admin";
}
/*CODE*/
}
#RequestMapping(value="/lock", method = RequestMethod.POST)
public #ResponseBody Status lockDevice(#ModelAttribute("adminTransaction") #Validated AdminTransaction adminTransaction, BindingResult result, Model model, Locale locale,Map<String, Object> map, HttpServletRequest request, #RequestParam #DateTimeFormat(pattern="yyyy-MM-dd") Date dueDate) {
try {
if(result.hasErrors()){
return "admin";
}
/*CODE*/
}
#RequestMapping(value="/unlock", method = RequestMethod.POST)
public #ResponseBody Status unlockDevice(#ModelAttribute("adminTransaction") #Validated AdminTransaction adminTransaction, BindingResult result, Model model, Locale locale,Map<String, Object> map, HttpServletRequest request) {
try {
if(result.hasErrors()){
return "admin";
}
/*CODE*/
}
admin.jsp
<div class="tabs" align="center">
<div class="list-center">
<ul class="tab-links">
<li class="active">Register</li>
<li>Lock</li>
<li>Unlock</li>
</ul>
</div>
<div class="tab-content">
<div id="tab1" class="tab active">
<div class="devices">
<form:form method="post" id="registerForm" modelAttribute="deviceMaster" action="/DeviceManager/admin/register">
<form:errors path="*" cssClass="plErroMessage" element="div" />
<br>
<c:if test="${not empty serverError}">
<div id="serverError" class="plErroMessage">${serverError}</div>
</c:if>
<div>
<div class="plLabelSearch">Device Id:</div>
<div class="plinput"><form:input path="deviceId" type="text" size="29"/></div>
</div>
<div>
<div class="plLabelSearch">Home Whse:</div>
<div class="plselect">
<form:select path="warehouseHome">
<form:option value="NONE" label="------- Select One -------"/>
<form:option value="TR" label="TRAINING"/>
<form:options items="${homeWhseList}" itemValue="warehouseCode" itemLabel="warehouseCode"/>
</form:select>
</div>
</div>
<br>
<br>
<div>
<div class="plLabelSearch"> </div>
<div class="plinput"><a id="btnRegister" class="abutton">Register</a></div>
<div class="plinput"><a id="btnCancel1" class="abutton">Cancel</a></div>
</div>
</form:form>
</div>
</div>
<div id="tab2" class="tab">
<div class="devices" >
<form:form method="post" id="lockForm" modelAttribute="adminTransaction" action="/DeviceManager/admin/lock">
<form:errors path="*" cssClass="plErroMessage" element="div" />
<br>
<c:if test="${not empty serverError}">
<div id="serverError" class="plErroMessage">${serverError}</div>
</c:if>
<div>
<div class="plLabelSearch">Device Id:</div>
<div class="plinput"><form:input path="deviceId" size="29"/></div>
</div>
<div>
<div class="plLabelSearch">Reason Code:</div>
<div class="plselect">
<form:select path="reasonCodeForeignKey">
<form:option value="NONE" label="------- Select One -------" />
<form:options items="${reasonList}" itemValue="reasonCode" itemLabel="reasonDesc"/>
</form:select>
</div>
</div>
<div class="hidden" >
<div>
<div class="plLabelSearch">Away Whse:</div>
<div class="plselect">
<form:select path="awayWarehouse">
<form:option value="NONE" label="------- Select One -------" />
<form:options items="${homeWhseList}" itemValue="warehouseCode" itemLabel="warehouseCode"/>
</form:select>
</div>
</div>
<div>
<div class="plLabelSearch">Due Date:</div>
<div class="plinput"><form:input id="datepicker" path="dueDate" placeholder="yyyy-mm-dd"/></div>
</div>
<div>
<div class="plLabelSearch">IT Ticket:</div>
<div class="plinput"><form:input path="itTicket" value="" size="29"/></div>
</div>
</div>
<br>
<br>
<div>
<div class="plLabelSearch"> </div>
<div class="plinput"><a id="btnLock" class="abutton">Lock</a></div>
<div class="plinput"><a id="btnCancel2" class="abutton">Cancel</a></div>
</div>
</form:form>
</div>
</div>
<div id="tab3" class="tab">
<div class="devices" >
<form:form method="post" id="unlockForm" modelAttribute="adminTransaction" action="/DeviceManager/admin/unlock">
<form:errors path="*" cssClass="plErroMessage" element="div" />
<br>
<c:if test="${not empty serverError}">
<div id="serverError" class="plErroMessage">${serverError}</div>
</c:if>
<div>
<div class="plLabelSearch">Device Id:</div>
<div class="plinput"><form:input path="deviceId" size="29"/></div>
</div>
<br>
<br>
<div>
<div class="plLabelSearch"> </div>
<div class="plinput"><a id="btnUnlock" class="abutton">Unlock</a></div>
<div class="plinput"><a id="btnCancel3" class="abutton">Cancel</a></div>
</div>
</form:form>
</div>
</div>
Handled it using jQuery and kept selected tab active on refresh with Bootstrap 3
$(document).ready(function() {
var activeTab = localStorage.getItem('activeTab');
if(activeTab){
$('.tab-links a[href="' + activeTab + '"]').tab('show');
}
$('.tabs .tab-links a').on('click', function(e) {
var currentAttrValue = jQuery(this).attr('href');
localStorage.setItem('activeTab', currentAttrValue);
jQuery('.tabs ' + currentAttrValue).siblings().slideUp(400);
jQuery('.tabs ' + currentAttrValue).delay(400).slideDown(400);
jQuery(this).parent('li').addClass('active').siblings().removeClass('active');
e.preventDefault();
});
});