Spring Boot multiple controllers with the same mapping
My problem is very similar to this one: Spring Multiple MVC controllers with the same @RequestMapping
I am creating a simple HR web application using Spring Boot. I have a list of jobs and an individual URL for each job:
local: 8080 / work / 1
This page contains job vacancies and a form that unauthorized users -applicants, in this case, can use to apply this job. Authenticated -HR Manager- users can only see the transaction data, not the form. I am having problems validating form input.
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 might have guessed, it didn't work because I couldn't get the models. So I put handleApplyForm()
in JobController
and changed a little:
@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);
}
}
This way the validations work, but I still can't get the same effect here as it refreshes the page so that all valid inputs disappear and no error messages appear.
By the way, job_detail.html
it looks 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>
source to share
Check thymeleaf documentation here
The th: field attribute values must be selection expressions (* {...}),
Also displayed ApplyForm
, then you can catch it in the form.
Then your form should look 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>
source to share