How to configure search by keyword in springboot jpa - spring

CustomerRepository.java
#Repository
public interface CustomerRepository extends JpaRepository<Customer,Long> {
#Query("SELECT c FROM Customer c WHERE c.name LIKE %?1%")
public List<Customer> search(String Keyword);
}
CustomerService.java
public List<Customer> listall(String keyword) {
if(keyword != null) {
return customerRepository.search(keyword);
}
else {
return customerRepository.findAll();
}
}
CustomerController.java
#GetMapping("/customer")
public String findAllCustomers(Model model,#Param("keyword") String keyword) {
List<Customer> listcustomer = customerService.listall(keyword);
model.addAttribute("listcustomer",listcustomer);
model.addAttribute("keyword",keyword);
model.addAttribute("customers", customerService.findAllCustomers());
return "customer";
}
customer.html
<form th:action="#{/customer}">
<div class="col-lg-3">
<input type="text" name="keyword" id="keyword" class="form-control" th:value="${keyword}">
</div>
<div class="col-lg-3">
<input type="submit" class="btn btn-success form-control">
</div>
</form>
Here i want to search and retrieve the customer name based on keyword,but on putting the keyword on search input and hitting the button just reloads the page with the URl "http://localhost:8080/customer?keyword=val".

Related

Passing form data from View Component to Controller in .NET Core MVC

I have a Component View and I try to update data from a form in it, I call the controller but in the controller I receive null :
public class CustomerPropertyViewComponent: ViewComponent
{
private MyDBContext context;
public CustomerPropertyViewComponent(MyDBContext _contex)
{
context = _contex;
}
public async Task<IViewComponentResult> InvokeAsync(int id)
{
CustomerPropertyModelView c = new CustomerPropertyModelView();
TblCustomerProperty t = new TblCustomerProperty(context);
c = t.getAllInfo(id);
if (c.model == null)
{
c.model = new TblCustomerProperty();
c.model.CustomerId = id;
}
return View(c);
}
}
and in the view I have
#model SunSystemDotNetCoreVersion.Models.helpers.CustomerPropertyModelView
<form asp-action="Update" asp-controller="CustomerProperties"
data-ajax="true"
data-ajax-method="POST"
method="post">
<div class="row w-100">
<div class="col-6">
<div class="row align-items-center h-100">
<div class="col-5 text-right">
Number of Bedrooms
</div>
<div class="col-7 p-1 p-1">
#Html.TextBoxFor(model => model.model.Bedrooms, new { #class = "form-control", Type = "number" })
</div>
<div class="col-5 text-right">
Current Heating System
</div>
<div class="col-7 p-1">
<select asp-for="model.HeatingSystemTypeId" class="form-control"
asp-items="#(new SelectList(Model.HeatingsList,"HeatingSystemTypeId","Title"))">
<option value="0">-Plaese Select-</option>
</select>
</div>
.....
<div class="col-12">
<button type="submit" >Save</button>
</div>
</div>
</form>
I have reduced most of the view code but it contains all data that the model needs. and this is my controller:
public class CustomerPropertiesController : Controller
{
private readonly MyDBContext_context;
public CustomerPropertiesController(MyDBContextcontext)
{
_context = context;
}
public IActionResult Update(TblCustomerProperty modelView) {
//here modelView is null
return View();
}
it should be work I don't know why it keeps sending null to my controller.
You could F12 to check the html elements in browser,and you will find the name of these elements are like:model.Bedrooms.Because your main model is CustomerPropertyModelView but your input belongs to TblCustomerProperty which named model in CustomerPropertyModelView.If your backend code recieve CustomerPropertyModelView as parameter,it will not be null.But if you recieve TblCustomerProperty as parameter,you need specify the suffix.
Change like below:
public IActionResult Update([Bind(Prefix ="model")]TblCustomerProperty modelView)
{
return View();
}

Spring #ModelAttributes auto binding

Hi i am tring to use #ModelAttributes for auto binding from view to controller.
this jsp page should send all elements which is Personal Schedule VO.
<form name="insertFrm" action="myScheduleInsert" method="POST">
<ul>
<input type="hidden" class="form-control" name="perschd_num" >
<li>
<label class='control-label'>title</label>
<input type="text" class="form-control" name="perschd_title" >
</li>
<li>
<input type="hidden" class="form-control" name="perschd_writer" >
<li>
<label class='control-label'>start date</label>
<input type="date" id="fullYear" class="form-control" name="perschd_start_date" value="">
</li>
<li>
<label class='control-label'>end date</label>
<input type="date" class="form-control" name="perschd_end_date" >
</li>
<li>
<label class='control-label'>content</label>
<input type="text" class="form-control" name="perschd_cont" >
</li>
</ul>
</div>
<!-- button-->
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<input type="submit" class="btn btn-primary">
</form>
and this is my controller for insert feature by using #ModelAttributes PerschdVO perschd and when i try print all out, all is null.
//insertSchedule
#RequestMapping("/myScheduleInsert")
public String myScheduleInsert(#ModelAttribute PerschdVO perschdVO ){
String view="redirect:/professor/mypage/mySchedule";
*System.out.println(perschdVO);*
try {
proService.insertPerschd(perschdVO);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return view;
}
and this is PerschdVO
public class PerschdVO {
private int perschd_num;
private String perschd_title;
private String perschd_cont;
private Date perschd_date;
private String perschd_start_date;
private String perschd_end_date;
private String perschd_writer; //id
public String getPerschd_writer() {
return perschd_writer;
}
public void setPerschd_writer(String perschd_writer) {
this.perschd_writer = perschd_writer;
}
public int getPerschd_num() {
return perschd_num;
}
public void setPerschd_num(int perschd_num) {
this.perschd_num = perschd_num;
}
public String getPerschd_title() {
return perschd_title;
}
public void setPerschd_title(String perschd_title) {
this.perschd_title = perschd_title;
}
public String getPerschd_cont() {
return perschd_cont;
}
public void setPerschd_cont(String perschd_cont) {
this.perschd_cont = perschd_cont;
}
public Date getPerschd_date() {
return perschd_date;
}
public void setPerschd_date(Date perschd_date) {
this.perschd_date = perschd_date;
}
public String getPerschd_start_date() {
return perschd_start_date;
}
public void setPerschd_start_date(String perschd_start_date) {
this.perschd_start_date = perschd_start_date;
}
public String getPerschd_end_date() {
return perschd_end_date;
}
public void setPerschd_end_date(String perschd_end_date) {
this.perschd_end_date = perschd_end_date;
}
why this elements from jsp does not match with this? Eventhough i matched all name in jsp file to PerschdVO's get() names.
and if i fix like this
public String myScheduleInsert(
Principal who,
#RequestParam("perschd_start_date")String perschd_start_date,
#RequestParam("perschd_end_date")String perschd_end_date,
#RequestParam("perschd_title")String perschd_title,
#RequestParam("perschd_cont")String perschd_cont
){
PerschdVO perschdVO = new PerschdVO();
...}
than the data from jsp could be sent to #Controller, but still can't get informations about using #ModelAttributes. cos if i use that always 400 bad request happened.

Listbox for MVC 6 EF 7 Property not Populating

I've been trying for a while now to get a list box to populate and I can't seem to figure it out. I've studied entity framework 7 documentation pretty extensively but I'm still new to it. There aren't a lot of tutorials out there for MVC6/EF7 yet so its been hard to know what the best practice is for associating one entity class with an instance of another. Please excuse the length of the question, I'm just trying to be thorough.
I'm using entity framework 7, asp.net 5 and MVC 6.
Steps To Reproduce Issue
Create a new ASP.Net Web Application → Name of project: ListBox.Web → Name of solution ListBox
Choose APS.NET 5 Templates → Web Application
Create two classes in the Models folder
Parent.cs
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace ListBox.Web.Models
{
public class Parent
{
public int ParentId { get; set; }
[Required]
public string Name { get; set; }
public ICollection<Child> Children { get; set; }
}
}
Child.cs
using System.ComponentModel.DataAnnotations;
namespace ListBox.Web.Models
{
public class Child
{
public int ChildId { get; set; }
[Required]
public string Name { get; set; }
public int ParentId { get; set; }
public Parent Parent { get; set; }
}
}
Create controllers and views for each of the data classes using scaffolding
Add links to the controllers in _Layout.cshtml
<ul class="nav navbar-nav">
<li><a asp-controller="Home" asp-action="Index">Home</a></li>
<li><a asp-controller="Parents" asp-action="Index">Parents</a></li>
<li><a asp-controller="Children" asp-action="Index">Children</a></li>
<li><a asp-controller="Home" asp-action="About">About</a></li>
<li><a asp-controller="Home" asp-action="Contact">Contact</a></li>
</ul>
Create the database
ListBox\src\ListBox.Web>dns ef migrations add Initial
ListBox\src\ListBox.Web>dnx ef database update
Run the web application
Add a couple parents.
Attempt to add a child.
A drop box is shown for parents but there are no items in the drop box to select
The HTML for the list box is: <select class="form-control" data-val="true" data-val-required="The ParentId field is required." id="ParentId" name="ParentId"></select>
Controller Source Code
using System.Linq;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.Data.Entity;
using ListBox.Web.Models;
namespace ListBox.Web.Controllers
{
public class ChildrenController : Controller
{
private ApplicationDbContext _context;
public ChildrenController(ApplicationDbContext context)
{
_context = context;
}
// GET: Children
public IActionResult Index()
{
var applicationDbContext = _context.Child.Include(c => c.Parent);
return View(applicationDbContext.ToList());
}
// GET: Children/Details/5
public IActionResult Details(int? id)
{
if (id == null)
{
return HttpNotFound();
}
Child child = _context.Child.Single(m => m.ChildId == id);
if (child == null)
{
return HttpNotFound();
}
return View(child);
}
// GET: Children/Create
public IActionResult Create()
{
ViewData["ParentId"] = new SelectList(_context.Set<Parent>(), "ParentId", "Parent");
return View();
}
// POST: Children/Create
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(Child child)
{
if (ModelState.IsValid)
{
_context.Child.Add(child);
_context.SaveChanges();
return RedirectToAction("Index");
}
ViewData["ParentId"] = new SelectList(_context.Set<Parent>(), "ParentId", "Parent", child.ParentId);
return View(child);
}
// GET: Children/Edit/5
public IActionResult Edit(int? id)
{
if (id == null)
{
return HttpNotFound();
}
Child child = _context.Child.Single(m => m.ChildId == id);
if (child == null)
{
return HttpNotFound();
}
ViewData["ParentId"] = new SelectList(_context.Set<Parent>(), "ParentId", "Parent", child.ParentId);
return View(child);
}
// POST: Children/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(Child child)
{
if (ModelState.IsValid)
{
_context.Update(child);
_context.SaveChanges();
return RedirectToAction("Index");
}
ViewData["ParentId"] = new SelectList(_context.Set<Parent>(), "ParentId", "Parent", child.ParentId);
return View(child);
}
// GET: Children/Delete/5
[ActionName("Delete")]
public IActionResult Delete(int? id)
{
if (id == null)
{
return HttpNotFound();
}
Child child = _context.Child.Single(m => m.ChildId == id);
if (child == null)
{
return HttpNotFound();
}
return View(child);
}
// POST: Children/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public IActionResult DeleteConfirmed(int id)
{
Child child = _context.Child.Single(m => m.ChildId == id);
_context.Child.Remove(child);
_context.SaveChanges();
return RedirectToAction("Index");
}
}
}
Child Create.cshtml
#model ListBox.Web.Models.Child
#{
ViewData["Title"] = "Create";
}
<h2>Create</h2>
<form asp-action="Create">
<div class="form-horizontal">
<h4>Child</h4>
<hr />
<div asp-validation-summary="ValidationSummary.ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Name" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger" />
</div>
</div>
<div class="form-group">
<label asp-for="ParentId" class="col-md-2 control-label"></label>
<div class="col-md-10">
<select asp-for="ParentId" class ="form-control"></select>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
</form>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
}
Change Create() method in ChildrenController, change
public IActionResult Create()
{
ViewData["ParentId"] = new SelectList(_context.Set<Parent>(), "ParentId", "Parent");
return View();
}
to
public IActionResult Create()
{
ViewData["ParentId"] = new SelectList(_context.Set<Parent>(), "ParentId", "Name");
return View();
}
In Create.cshtml, change
<select asp-for="ParentId" class="form-control"></select>
to
#Html.DropDownList("ParentId", null, htmlAttributes: new { #class = "form-control" })
The generated code is incorrect, it is a bug https://github.com/aspnet/Scaffolding/issues/149
One solution using "tag helpers" is:
Controller
...
ViewData["Parents"] = new SelectList(_context.Set<Parent>(), "ParentId", "Name", child.ParentId);
...
View
#{
var parents = (IEnumerable<SelectListItem>)ViewData["Parents"];
}
...
<select asp-for="ParentId" asp-items="parents" class ="form-control">
<option disabled selected>--- SELECT ---</option>
</select>
...
Here's how to do it when there is only one type of object which is nested within another object of the same type.
Object:
public class Fleet
{
public int Id { get; set; }
public Fleet ParentFleet { get; set; }
public int? ParentFleetId { get; set; }
public string Name { get; set; }
[InverseProperty("ParentFleet")]
public virtual List<Fleet> Children { get; set; }
public List<UserFleet> UserFleets { get; set; }
}
Controller:
ViewData["ParentFleetId"] = new SelectList(_context.Set<Fleet>(), "Id", "Name");
return View();
View:
<form asp-action="Create">
<div class="form-horizontal">
<h4>Fleet</h4>
<hr />
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Name" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger" />
</div>
</div>
<div class="form-group">
<label asp-for="ParentFleet" class="col-md-2 control-label"></label>
<div class="col-md-10">
<select asp-for="ParentFleetId" asp-items="ViewBag.ParentFleetId" class="form-control">
<option value=""></option>
</select>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
</form>

Can't get selected option in controller

I have a form to list up buckets in select options, it uploads file to bucket after select bucket and file, but I can't get selected bucket in my controller, The folder alwsy return empty string, though mutipartFile is no problem, I really want to know why!
I googled for all this week but no result what I need!
I am very new in thymeleaf even in spring framework:(
Pls help me to solve this simple problem to you:)
part of html file as below:
<form role="form" enctype="multipart/form-data" action="#" th:object="${folder}" th:action="#{'/drill/skin/upload'}" method="POST">
<div class="form-group">
<label class="form-control-static">Select Bucket</label>
<select class="form-control" th:field="${folder}">
<option th:each="bucket : ${buckets}" th:value="${bucket.name}" th:text="${bucket.name}">bucket</option>
</select>
</div>
<label class="form-control-static" for="inputSuccess">Select Upload File</label>
<div class="form-group">
<input type="file" class="form-control" name="uploadFile"/>
</div>
<div class="form-group">
<button class="btn btn-primary center-block" type="submit">Upload</button>
</div>
</form>
controller as below:
#RequestMapping(value="/", method=RequestMethod.GET)
public String provideUploadInfo(Model model) {
List<Bucket> buckets = s3Service.listBuckets();
model.addAttribute("buckets", buckets);
model.addAttribute("folder", "com.smartstudy");
return "index";
}
#RequestMapping(value="/upload", method=RequestMethod.POST)
public String handleFileUpload(
#ModelAttribute("folder") String folder,
#RequestParam("uploadFile") MultipartFile uploadFile, Model model) {
log.info("Bucket: " + folder + ", uploadFile: " + uploadFile.getOriginalFilename());
if (!uploadFile.isEmpty() && !folder.isEmpty()) {
return s3Service.upload(uploadFile, folder);
}
return "index";
}
There are couple of issues in your code.
Ideally, the whole form should be encapsulated in one form-backing object. In your case, create a Java object that wraps the folder and the file together.
class BucketFileForm{
private MultipartFile uploadFile;
private String folder;
public String getFolder() {
return folder;
}
public void setFolder(String folder) {
this.folder = folder;
}
public MultipartFile getUploadFile() {
return uploadFile;
}
public void setUploadFile(MultipartFile uploadFile) {
this.uploadFile = uploadFile;
}
}
Make this object available in the model so that you can access it in the view
#RequestMapping(value="/", method=RequestMethod.GET)
public String provideUploadInfo(Model model) {
List<Bucket> buckets = s3Service.listBuckets();
model.addAttribute("buckets", buckets);
//replace this
//model.addAttribute("folder", "com.smartstudy");
//with
BucketFileForm bucketFileForm = new BucketFileForm();
bucketFileForm.setFolder("com.smartstudy");
model.addAttribute("bucketFileForm", bucketFileForm);
return "index";
}
Now, use this form-backing object in the form
<form role="form" enctype="multipart/form-data" action="#" th:object="${bucketFileForm}" th:action="#{'/drill/skin/upload'}" method="POST">
<div class="form-group">
<label class="form-control-static">Select Bucket</label>
<select class="form-control" th:field="*{folder}">
<option th:each="bucket : ${buckets}" th:value="${bucket.name}" th:text="${bucket.name}">bucket</option>
</select>
</div>
<label class="form-control-static" for="inputSuccess">Select Upload File</label>
<div class="form-group">
<input type="file" th:field="*{uploadFile}" class="form-control" name="uploadFile"/>
</div>
<div class="form-group">
<button class="btn btn-primary center-block" type="submit">Upload</button>
</div>
</form>
Then modify your POST endpoint to accomodate these changes.
#RequestMapping(value="/upload", method=RequestMethod.POST)
public String handleFileUpload(#ModelAttribute("bucketFileForm") final BucketFileForm form, final BindingResult bindingResult, Model model) {
log.info("Bucket: " + form.getFolder() + ", uploadFile: " + form.getUploadFile().getOriginalFilename());
if (!form.getUploadFile().isEmpty() && !form.getFolder().isEmpty()) {
return s3Service.upload(uploadFile, folder);
}
return "index";
}

Spring Boot multiple controllers with same mapping

My problem is very similar with this one: Spring MVC Multiple Controllers with same #RequestMapping
I'm building simple Human Resources web application with Spring Boot. I have a list of jobs and individual url for each job:
localhost:8080/jobs/1
This page contains job posting details and a form which unauthenticated users -applicants, in this case- can use to apply this job. Authenticated users -HR Manager-, can see only posting details, not the form. I have trouble with validating form inputs.
What I tried first:
#Controller
public class ApplicationController {
private final AppService appService;
#Autowired
public ApplicationController(AppService appService) {
this.appService = appService;
}
#RequestMapping(value = "/jobs/{id}", method = RequestMethod.POST)
public String handleApplyForm(#PathVariable Long id, #Valid #ModelAttribute("form") ApplyForm form, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return "job_detail"; //HTML page which contains job details and the application form
}
appService.apply(form, id);
return "redirect:/jobs";
}
#RequestMapping(value = "/applications/{id}", method = RequestMethod.GET)
public ModelAndView getApplicationPage(#PathVariable Long id) {
if (null == appService.getAppById(id)) {
throw new NoSuchElementException(String.format("Application=%s not found", id));
} else {
return new ModelAndView("application_detail", "app", appService.getAppById(id));
}
}
}
As you guess this didn't work because I couldn't get the models. So I put handleApplyForm() to JobController and changed a little bit:
#Controller
public class JobController {
private final JobService jobService;
private final AppService appService;
#Autowired
public JobController(JobService jobService, AppService appService) {
this.jobService = jobService;
this.appService = appService;
}
#RequestMapping(value = "/jobs/{id}", method = RequestMethod.POST)
public ModelAndView handleApplyForm(#PathVariable Long id, #Valid #ModelAttribute("form") ApplyForm form, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return getJobPage(id);
}
appService.apply(form, id);
return new ModelAndView("redirect:/jobs");
}
#RequestMapping(value = "/jobs/{id}", method = RequestMethod.GET)
public ModelAndView getJobPage(#PathVariable Long id) {
Map<String, Object> model = new HashMap<String, Object>();
if (null == jobService.getJobById(id)) {
throw new NoSuchElementException(String.format("Job=%s not found", id));
} else {
model.put("job", jobService.getJobById(id));
model.put("form", new ApplyForm());
}
return new ModelAndView("job_detail", model);
}
}
With this way, validations works but I still can't get the same effect here as it refreshes the page so that all valid inputs disappear and error messages don't appear.
By the way, job_detail.html is like this:
<h1>Job Details</h1>
<p th:inline="text"><strong>Title:</strong> [[${job.title}]]</p>
<p th:inline="text"><strong>Description:</strong> [[${job.description}]]</p>
<p th:inline="text"><strong>Number of people to hire:</strong> [[${job.numPeopleToHire}]]</p>
<p th:inline="text"><strong>Last application date:</strong> [[${job.lastDate}]]</p>
<div sec:authorize="isAuthenticated()">
<form th:action="#{/jobs/} + ${job.id}" method="post">
<input type="submit" value="Delete this posting" name="delete" />
</form>
</div>
<div sec:authorize="isAnonymous()">
<h1>Application Form</h1>
<form action="#" th:action="#{/jobs/} + ${job.id}" method="post">
<div>
<label>First name</label>
<input type="text" name="firstName" th:value="${form.firstName}" />
<td th:if="${#fields.hasErrors('form.firstName')}" th:errors="${form.firstName}"></td>
</div>
<!-- and other input fields -->
<input type="submit" value="Submit" name="apply" /> <input type="reset" value="Reset" />
</form>
</div>
Check thymeleaf documentation here
Values for th:field attributes must be selection expressions (*{...}),
Also ApplyForm is exposed then you can catch it in the form.
Then your form should looks like this:
<form action="#" th:action="#{/jobs/} + ${job.id}" th:object="${applyForm}" method="post">
<div>
<label>First name</label>
<input type="text" name="firstName" th:value="*{firstName}" />
<td th:if="${#fields.hasErrors('firstName')}" th:errors="*{firstName}"></td>
</div>
<!-- and other input fields -->
<input type="submit" value="Submit" name="apply" /> <input type="reset" value="Reset" />
</form>

Resources