i've been asked to learn java and spring mvc for work but seems i'm not really good at it :(
Anyway i'm trying to create two lists dynamically the first one works, the second doesn't (i didn't really understand the get and post methods i fear) can you tell me why?
#Controller
#RequestMapping(value = "/")
public class ConfigController {
#RequestMapping(value = "home", method = RequestMethod.GET)
public String saveNum(Model model) {
model.addAttribute("configuration", new Config());
return "home";
}
#RequestMapping(value = "home", method = RequestMethod.POST)
public String saveNumPost(#ModelAttribute(value = "configuration") Config config, Model model) {
List<Driver> drivers = new ArrayList<Driver>();
for (int i = 0; i < config.getDriversNum(); i++) {
drivers.add(new Driver());
}
Championship championship = new Championship();
championship.setDrivers(drivers);
model.addAttribute("championship", championship);
return "configDrivers";
}
#RequestMapping(value = "configDrivers", method = RequestMethod.GET)
public String saveDriverList() {
return "configDrivers";
}
#RequestMapping(value = "configDrivers", method = RequestMethod.POST)
public String createCars(#ModelAttribute Championship championship, Config config, Model model) {
List<Car> cars = new ArrayList<Car>();
for (int i = 0; i < championship.getDrivers().size(); i++) {
cars.add(new Car());
}
championship.setCars(cars);
model.addAttribute("championship", championship);
return "configCars";
}
#RequestMapping(value = "configCars", method = RequestMethod.GET)
public String saveTrackNum(#ModelAttribute Config config, Model model) {
model.addAttribute("configuration", config);
return "trackNum";
}
#RequestMapping(value = "trackNum", method = RequestMethod.POST)
public String saveTracks(#ModelAttribute(value = "configuration") Config config, Championship championship,
Model model) {
List<Track> tracks = new ArrayList<Track>();
for (int i = 0; i < config.getTracksNum(); i++) {
tracks.add(new Track());
}
championship.setTracks(tracks);
model.addAttribute("championship", championship);
return "configTracks";
}
}
home view
<c:url var="url" value="/home"/>
<form:form action="${url}" method="POST" modelAttribute="configuration">
<label>Insert number of drivers:</label> <br>
<form:input path="driversNum" placeholder="Type drivers number"/>
<br>
<input type="submit" />
<!--number races-->
</form:form>
configDrivers view
<c:url var="url" value="/configDrivers"/>
<form:form action="${url}" method="POST" modelAttribute="championship">
<label>Insert drivers:</label>
<c:forEach items="${championship.drivers}" var="driver" varStatus="i">
<h3>Insert driver's name and surname of driver ${i.index} </h3>
<form:input path="drivers[${i.index}].name" value="${driver.name}" placeholder="Type name here" />
<br>
<form:input path="drivers[${i.index}].surname" value="${driver.surname}" placeholder="Type surname here" />
<br>
</c:forEach>
<input type="submit" />
<!--number races-->
</form:form>
configCars view
<c:url var="url" value="/configCars"/>
<form:form action="${url}" method="POST" modelAttribute="championship">
<label>Insert cars:</label>
<c:forEach items="${championship.cars}" var="car" varStatus="i">
<h3>Insert driver's team ${i.index} </h3>
<form:input path="cars[${i.index}].team" value="${car.team}" placeholder="Type team here" />
<br>
</c:forEach>
<input type="submit" />
<!--number races-->
</form:form>
<select>
<c:forEach items="${championship.drivers}" var="car" varStatus="i">
<option value="${i.index}">${driver.name}</option>
</c:forEach>
</select>
the Car class
public class Car {
private String team;
private Driver driver;
public String getTeam() {
return team;
}
public void setTeam(String team) {
this.team = team;
}
public Driver getDriver() {
return driver;
}
public void setDriver(Driver driver) {
this.driver = driver;
}
}
an the championship class (the one with the lists)
public class Championship {
private List<Driver> drivers;
private List<Car> cars;
private List<Track> tracks;
public List<Driver> getDrivers() {
return drivers;
}
public void setDrivers(List<Driver> drivers) {
this.drivers = drivers;
}
public List<Car> getCars() {
return cars;
}
public void setCars(List<Car> cars) {
this.cars = cars;
}
public List<Track> getTracks() {
return tracks;
}
public void setTracks(List<Track> tracks) {
this.tracks = tracks;
}
}
Can you paste this code :
List<Car> cars = new ArrayList<Car>();
for (int i= 0; i < config.getDriversNum(); i++) {
cars.add(new Car());
}
Championship championship = new Championship();
championship.setCars(cars);
model.addAttribute("championship",championship);
inside the printDrivers() method and check.
I think that should do the trick.
Related
Trying to access multiple objects in the POST method using SpringBoot MVC and thymeleaf.
here is the controller.
#Controller
public class PatientController {
ObjectMapper Obj = new ObjectMapper();
#GetMapping("/patient")
public static String patientForm(Model model) {
model.addAttribute("patient", new PatientDataModel());
model.addAttribute("patient1", new PatientDataModel1());
return "patient";
}
#RequestMapping(value="/patient", method=RequestMethod.POST, params="action=Send data to MongoDB cluster")
public static String patientSubmit(#ModelAttribute("patient") PatientDataModel patient, #ModelAttribute("patient1") PatientDataModel patient1, Model model, Object obj ) throws JsonProcessingException {
model.addAttribute("patient", patient);
model.addAttribute("patient1", patient1);
return "result";
}
and here are the views:
patient.html
<form action="#" th:action="#{/patient}" th:object="${patient}" method="post">
<div th:object="${patient1}" >
<p>Patient Id: <input type="text" th:value="${patient.id}" /></p>
<p>Patient Name: <input type="text" th:value="${patient.name}" /></p>
<p>Message: <input type="text" th:value="${patient.content}" /></p>
<p>address: <input type="text" th:value="${patient1.address}" /></p>
</div>
<p><input type="submit" name="action" value="Send data to MongoDB cluster" />
<input type="reset" value="Reset" /></p>
</form>
</div>
and result.html
<div class="starter-template">
<h1>Result</h1>
<p th:text="'id: ' + ${patient.id}" />
<p th:text="'Name: ' + ${patient.name}" />
<p th:text="'content: ' + ${patient.content}" />
<p th:text="'address: ' + ${patient1.address}" />
Submit another message
</div>
and the bean classes are : PatientDataModel.java
public class PatientDataModel {
private long id;
private String content;
private String name;
public PatientDataModel()
{
}
public PatientDataModel(long id, String content, String name)
{
this.id = id;
this.content = content;
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
#Override
public String toString()
{
return "Patient [id=" + id + ", firstName=" + name + ", " +
"content=" + content + "]";
}
}
another bean :
public class PatientDataModel1 {
private String address;
#Override
public String toString() {
return "Patient1 [address=" + address + "]";
}
public PatientDataModel1()
{
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
now , the issue is , I need both the beans to be accessible in the GET and POST method.
when I am running the code , it is executing but the beans does not have values , all are null . pls suggest
It will be easiest to have 1 object to find to the form. Create a new class PatientFormData for example that contains all the fields from the 2 objects and convert from/to the objects you have in the get and post methods in your controller.
For example:
public class PatientFormData {
private long id;
private String content;
private String name;
private String address;
public static PatientFormData from(PatientDataModel model,
PatientDataModel1 model1) {
id = model.getId();
content = model.getContent();
name = model.getName();
address = model.getAddress();
}
public PatientDataModel createPatientDataModel() {
PatientDataModel result = new PatientDataModel();
result.setId(id);
result.setContent(content);
result.setName(name);
return result;
}
// getters and setters here
}
Use this in the controller:
#Controller
public class PatientController {
ObjectMapper Obj = new ObjectMapper();
#GetMapping("/patient")
public static String patientForm(Model model) {
PatientFormData formData = PatientFormData.from(new PatientDataModel(), new PatientDataModel1());
model.addAttribute("patientFormData", formData);
return "patient";
}
#RequestMapping(value="/patient", method=RequestMethod.POST, params="action=Send data to MongoDB cluster")
public static String patientSubmit(#ModelAttribute("patientFormData") PatientFormData formData, Model model, Object obj ) throws JsonProcessingException {
PatientDataModel model = formData.createPatientDataModel();
PatientDataModel1 model1 = formData.createPatientDataModel1();
// Do more processing with objects
return "result";
}
Also be sure to correctly use the field binding using *{..}:
<form action="#" th:action="#{/patient}" th:object="${patientFormData}" method="post">
<p>Patient Id: <input type="text" th:value="*{id}" /></p>
<p>Patient Name: <input type="text" th:value="*{name}" /></p>
<p>Message: <input type="text" th:value="*{content}" /></p>
<p>address: <input type="text" th:value="*{address}" /></p>
</div>
<p><input type="submit" name="action" value="Send data to MongoDB cluster" />
<input type="reset" value="Reset" /></p>
</form>
</div>
My question is How can I use my getLabel, getX, getY from my NodeEntity class and display the results of my query on my web page instead of getting "org.neo4j.ogm.response.model". I do not know if these get methods should be used within the controller or repository class in order to display the node information on the web page table.
#NodeEntity
public class Room {
#Id #GeneratedValue
private Long id;
#Property(name = "label")
private String label;
#Property(name = "shape")
private String shape;
#Property(name = "colour")
private String colour;
#Property(name = "x")
private String x;
#Property(name = "y")
private String y;
#Relationship(type = "To")
private Collection<Room> roomTo = new ArrayList<>();
#Relationship(type = "Up")
private Collection<Room> roomUp = new ArrayList<>();
#Relationship(type = "Down")
private Collection<Room> roomDown = new ArrayList<>();
#JsonIgnoreProperties("room")
#Relationship(type = "To", direction = Relationship.INCOMING)
Collection<RelEnt> relEnts;
public Room(){
}
public String getLabel(){
return label;
}
public String getShape(){
return shape;
}
public String getColour(){
return colour;
}
public String getX() {
return x;
}
public String getY() {
return y;
}
}
Repository:
public interface NavigatorRepository extends Neo4jRepository<Room, String>{
#Query("match (r1: Room {label: {from}}), (r2: Room {label: {to}}), p = shortestPath((r1)-[*]-(r2)) unwind nodes(p) as room return room")
Iterable<Map<String, Object>> getShortestRoute(#Param("from") String from, #Param("to") String to);
}
Service:
#Service
public class NavigatorService {
#Autowired
NavigatorRepository navigatorRepository;
public Iterable<Map<String, Object>> shortestRoute(String from, String to){
return navigatorRepository.getShortestRoute(from, to);
}
}
Controller:
#Controller
public class AunController {
#RequestMapping(value = "/AUN") //this will allow you to access web page with just http://localhost:8081/
public String homePage(){
return "AUN-Web"; //uses the static html file created for the web page
}
#Autowired
NavigatorService navigatorService;
#GetMapping(value = "/navigate")
public String navigate(#RequestParam(name="from") String from, #RequestParam(name="to") String to, Model model) {
Iterable<Map<String, Object>> route = navigatorService.shortestRoute(from, to);
model.addAttribute("from", from)
.addAttribute("route", route)
.addAttribute("to", to);
return "AUN-Results";
}
#GetMapping(value = "/")
public String error(){
return "Error/404";
}
}
HTML:
<form action="/navigate" method="">
<strong><label for="ifrom">Current Location:</label></strong> <br>
<input id="ifrom" type="text" placeholder="MB" name="from"><br>
<strong><label for="ito">Destination:</label></strong> <br>
<input id="ito" type="text" placeholder="MB" name="to"><br>
<p style="line-height: 30px; width: 300px;"></p>
<button type="button" class="btn btn-success" onclick="result">Search</button>
<p style="line-height: 30px; width: 300px;"></p>
</form>
</div>
<div align="center" class="container-fluid">
<h5>Going from <span th:text="${from}">MB220</span> to <span th:text="${to}">MB265</span></h5>
<table class="table">
<tr>
<th>Label</th>
<th>X</th>
<th>Y</th>
</tr>
<tr th:each="route : ${route}">
<td th:text="${route}">Mb220</td>
</tr>
</table>
</div>
Try to change your foreach var name to something like "routpoint" so it differs to the complete route.
I have two webpages.One is "user.jsp" and "person.jsp".when i click on "Register" button it goes to "user.jsp" and when i click on submit button its showing "Http Status 400".
PersonController.java
#Controller
public class PersonController {
private PersonService personService;
private UserService userService;
#Autowired(required=true)
#Qualifier(value="personService")
public void setPersonService(PersonService ps){
this.personService = ps;
}
#RequestMapping(value = "/persons", method = RequestMethod.GET)
public String listPersons(Model model) {
model.addAttribute("person", new Person());
model.addAttribute("listPersons", this.personService.listPersons());
return "person";
}
//For add and update person both
#RequestMapping(value= "/person/add", method = RequestMethod.POST)
public String addPerson(#ModelAttribute("person") Person p,#ModelAttribute("user") User u){
String name = p.getName();
System.out.println("name is :"+name);
if(name == null || name == "") {
System.out.println("user is"+name);
return "user";
}
else{
//new person, add it
this.personService.addPerson(p);
}
return "redirect:/persons";
}
#RequestMapping(value = "/user/add", method = RequestMethod.POST)
public String addUser(#ModelAttribute("user") User user) {
// new user, add to DB
this.userService.addUser(user);
return "redirect:/persons";
}
PersonDAOImpl.java
#Repository
public class PersonDAOImpl implements PersonDAO {
private static final Logger logger = LoggerFactory.getLogger(PersonDAOImpl.class);
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sf){
this.sessionFactory = sf;
}
#Override
public void addPerson(Person p) {
Session session = this.sessionFactory.getCurrentSession();
session.persist(p);
logger.info("Person saved successfully, Person Details="+p);
}
#Override
public void updatePerson(Person p) {
Session session = this.sessionFactory.getCurrentSession();
session.update(p);
logger.info("Person updated successfully, Person Details="+p);
}
#SuppressWarnings("unchecked")
#Override
public List<Person> listPersons() {
Session session = this.sessionFactory.getCurrentSession();
List<Person> personsList = session.createQuery("from Person").list();
for(Person p : personsList){
logger.info("Person List::"+p);
}
return personsList;
}
#Override
public Person getPersonByName(String name) {
Session session = this.sessionFactory.getCurrentSession();
List<Person> usersList = session.createQuery(
"from Person ").list();
if (usersList.size() == 0)
return null;
Person usrObj1 = usersList.get(0);
return usrObj1;
}
UserDAOImpl.java
#Repository
public class UserDAOImpl implements UserDAO {
private static final Logger logger = LoggerFactory
.getLogger(UserDAOImpl.class);
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sf) {
this.sessionFactory = sf;
}
#Override
public void addUser(User user) {
Session session = this.sessionFactory.getCurrentSession();
session.persist(user);
logger.info("User saved successfully, User Details=" + user);
}
#Override
public void updateUser(User user) {
Session session = this.sessionFactory.getCurrentSession();
session.update(user);
logger.info("User updated successfully, User Details=" + user);
}
#SuppressWarnings("unchecked")
#Override
public List<User> listUsers() {
Session session = this.sessionFactory.getCurrentSession();
List<User> usersList = session.createQuery("from User").list();
for (User user : usersList) {
logger.info("User List::" + user);
}
return usersList;
}
#SuppressWarnings("unchecked")
#Override
public User getUserByName(String fullName) {
Session session = this.sessionFactory.getCurrentSession();
List<User> usersList = session.createQuery(
"from User ").list();
if (usersList.size() == 0)
return null;
User usrObj1 = usersList.get(0);
return usrObj1;
}
Person.java
#Entity
#Table(name="PERSON")
public class Person {
#Id
#Column(name="id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
private String name;
private String country;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
#Override
public String toString(){
return "id="+id+", name="+name+", country="+country;
}
}
User.java
#Entity
#Table(name = "user")
#XmlRootElement(name = "User")
public class User {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "fullname")
private String fullName;
#Column(name = "password")
private String password;
#Column(name = "email")
private String email;
#Column(name = "phone")
private Integer phone;
#XmlElement(name = "Id")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#XmlElement(name = "FullName")
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
#XmlElement(name = "Password")
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
#XmlElement(name = "EmailId")
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
#XmlElement(name = "PhoneNo")
public Integer getPhone() {
return phone;
}
public void setPhone(Integer phone) {
this.phone = phone;
}
PersonServiceImpl.java
#Service
public class PersonServiceImpl implements PersonService {
private PersonDAO personDAO;
public void setPersonDAO(PersonDAO personDAO) {
this.personDAO = personDAO;
}
#Override
#Transactional
public void addPerson(Person p) {
this.personDAO.addPerson(p);
}
#Override
#Transactional
public void updatePerson(Person p) {
this.personDAO.updatePerson(p);
}
#Override
#Transactional
public List<Person> listPersons() {
return this.personDAO.listPersons();
}
#Override
#Transactional
public Person getPersonById(int id) {
return this.personDAO.getPersonById(id);
}
#Override
#Transactional
public Person getPersonByName(String name) {
return this.personDAO.getPersonByName(name);
}
#Override
#Transactional
public void removePerson(int id) {
this.personDAO.removePerson(id);
}
UserServiceImpl.java
#Service
public class UserServiceImpl implements UserService {
private UserDAO userDAO;
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
#Override
#Transactional
public void addUser(User user) {
this.userDAO.addUser(user);
}
#Override
#Transactional
public void updateUser(User user) {
this.userDAO.updateUser(user);
}
#Override
#Transactional
public List<User> listUsers() {
return this.userDAO.listUsers();
}
#Override
#Transactional
public User getUserById(int id) {
return this.userDAO.getUserById(id);
}
#Override
#Transactional
public void removeUser(int id) {
this.userDAO.removeUser(id);
}
#Override
#Transactional
public User getUserByName(String fullName) {
return this.userDAO.getUserByName(fullName);
}
}
person.jsp
<c:url var="addAction" value="/person/add" ></c:url>
<form:form action="${addAction}" commandName="person">
<table>
<c:if test="${!empty person.name}">
<tr>
<td>
<form:label path="id">
<spring:message text="ID"/>
</form:label>
</td>
<td>
<form:input path="id" readonly="true" size="8" disabled="true" />
<form:hidden path="id" />
</td>
</tr>
</c:if>
<tr>
<td>
<form:label path="name">
<spring:message text="Name"/>
</form:label>
</td>
<td>
<form:input path="name" />
</td>
</tr>
<tr>
<td>
<form:label path="country">
<spring:message text="Country"/>
</form:label>
</td>
<td>
<form:input path="country" />
</td>
</tr>
<tr>
<td colspan="2">
<input type="submit"
value="<spring:message text="Add Person"/>" />
<input type="submit"
value="<spring:message text="Register"/>" />
</td>
</tr>
</table>
</form:form>
user.jsp
<c:url var="addAction" value="/user/add"></c:url>
<form:form action="${addAction}" commandName="user">
<table width="400px" height="150px">
<c:if test="${!empty user.email}">
<tr>
<td><form:label path="id">
<spring:message text="ID" />
</form:label></td>
<td><form:input path="id" readonly="true" size="8"
disabled="true" /> <form:hidden path="id" /></td>
</tr>
</c:if>
<c:if test="${!empty user.email}">
</c:if>
<tr>
<td><form:label path="fullName">
<spring:message text="Full Name" />
</form:label></td>
<td><form:input path="fullName" /></td>
</tr>
<tr>
<td><form:label path="password">
<spring:message text="Password" />
</form:label></td>
<td><form:input type="password" path="password" /></td>
</tr>
<tr>
<td><form:label path="email">
<spring:message text="Email" />
</form:label></td>
<td><form:input path="email" /></td>
</tr>
<tr>
<td><form:label path="phone">
<spring:message text="Phone" />
</form:label></td>
<td><form:input path="phone" /></td>
</tr>
<tr>
<td colspan="2"><c:if test="${!empty user.email}">
<input type="submit"
value="<spring:message text="Update Details"/>" />
</c:if> <c:if test="${empty user.email}">
<input type="submit" value="<spring:message text="Submit"/>" />
</c:if></td>
</tr>
</table>
</form:form>
Any suggestion or advice in this it will be helpful for me
THanking You
I hope this helps!
https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
400 Bad Request
The server cannot or will not process the request due to an apparent client error (e.g., malformed request syntax, too large size, invalid request message framing, or deceptive request routing).
You have not defined the http method attribute of your form:
<form:form action="${addAction}" commandName="user">
Then, the default method is GET, therefore it wont never found a controller because your controller /user/add expects RequestMethod.POST
If you add the method attribute It will work:
<form:form action="${addAction}" commandName="user" method="POST">
I'm creating a web application using Spring MVC, but all my POST request result in "The request sent by the client was syntactically incorrect". As an example, this is a search form:
<form id="projectsForm" action="#" th:action="#{/projects}" th:object="${projectsForm}" method="post">
<input type="hidden" th:field="*{page}" />
<div id="search">
<select id="expert" th:field="*{expert}">
<option value="">(select expert)</option>
<option th:each="expert : ${experts}"
th:value="${expert.id}"
th:text="${expert.firstName + ' ' + expert.lastName}"></option>
</select>
<select id="company" th:field="*{company}">
<option value="">(select company)</option>
<option th:each="company : ${companies}"
th:value="${company.id}"
th:text="${company.name}"></option>
</select>
<input type="text" id="query" th:field="*{query}" />
<button class="search" onclick="firstPage()">Search</button>
<button class="empty" onclick="empty()">Erase</button>
</div>
The form object class looks like this:
public class ProjectsForm {
private Expert expert;
private Company company;
private String query;
private Integer page = 0;
private Integer pages;
public Expert getExpert() {
return expert;
}
public void setExpert(Expert expert) {
this.expert = expert;
}
public Integer getPage() {
return page;
}
public void setPage(Integer page) {
this.page = page;
}
public Integer getPages() {
return pages;
}
public void setPages(Integer pages) {
if (pages > 0 && page >= pages) {
page = pages - 1;
}
this.pages = pages;
}
public Company getCompany() {
return company;
}
public void setCompany(Company company) {
this.company = company;
}
public String getQuery() {
return query;
}
public void setQuery(String query) {
this.query = query;
}
}
And this is the controller method:
#RequestMapping(value="/projects", method=RequestMethod.POST)
public String projectsPost(#ModelAttribute("projectsForm") ProjectsForm projectsForm, ModelMap model) {
sessionBean.setProjectsForm(projectsForm);
Page<Project> projectPage = projectService.findAll(projectsForm.getPage(), ProjectController.PAGESIZE, projectsForm.getExpert(), projectsForm.getCompany(), projectsForm.getQuery());
List<Project> projects = projectPage.getContent();
model.addAttribute("projects", projects);
projectsForm.setPage(projectPage.getNumber());
projectsForm.setPages(projectPage.getTotalPages());
model.addAttribute("projectsForm", projectsForm);
return "projects";
}
Chrome tells me the form data look like this:
page=0&expert=&company=&query=
Is there an obvious error, or is there any way I can diagnose this problem? Adding log4j.logger.org.springframework.web=DEBUG to log4j.properties didn't give me any more information. What also puzzles me is that the exact same code worked fine in a Spring Boot jar application.
In a spring mvc application that uses hibernate an jpa, I have a module for editing phone numbers which is not committing changes to the database when the user enters altered information for phone number and phone number type. I keep going over the code, but I cannot see where the problem is. Can someone show me what to change in the below?
Here are the relevant methods of PhoneNumberController.java:
#RequestMapping(value = "/patients/{patientId}/phonenumbers/{phonenumberId}/edit", method = RequestMethod.GET)
public String initUpdateForm(#PathVariable("phonenumberId") int phonenumberId, Map<String, Object> model) {
System.out.println("--------------------------------- made it into initUpdateForm() method");
PhoneNumber phonenumber = this.clinicService.findPhoneNumberById(phonenumberId);
model.put("phonenumber", phonenumber);
return "phonenumbers/createOrUpdatePhoneNumberForm";
}
#RequestMapping(value = "/patients/{patientId}/phonenumbers/{phonenumberId}/edit", method = {RequestMethod.PUT, RequestMethod.POST})
public String processUpdateForm(#ModelAttribute("phonenumber") PhoneNumber phonenumber, BindingResult result, SessionStatus status) {
// we're not using #Valid annotation here because it is easier to define such validation rule in Java
new PhoneNumberValidator().validate(phonenumber, result);
if (result.hasErrors()) {return "phonenumbers/createOrUpdatePhoneNumberForm";}
else {
this.clinicService.savePhoneNumber(phonenumber);
status.setComplete();
return "redirect:/patients?patientID={patientId}&type=phone";
}
}
Here is the PhoneNumber.java model:
#Entity
#Table(name = "patient_phone_numbers")
public class PhoneNumber {
#Id
#GeneratedValue
#Column(name="id")
private Integer id;
#ManyToOne
#JoinColumn(name = "client_id")
private Patient patient;
#Column(name="phonenumber")
private String number;
#ManyToOne
#JoinColumn(name = "type_id")
private PhoneNumberType type;
#Column(name = "preferred")
private boolean preferred;
#Column(name = "okmessages")
private boolean okmessages;
public Integer getId(){return id;}
public void setId(Integer i){id=i;}
protected void setPatient(Patient patient) {this.patient = patient;}
public Patient getPatient(){return this.patient;}
public String getNumber(){return number;}
public void setNumber(String pn){number=pn;}
public PhoneNumberType getType(){return this.type;}
public void setType(PhoneNumberType nt){this.type=nt;}
public boolean getPreferred(){return preferred;}
public void setPreferred(boolean p){preferred=p;}
public boolean getOkmessages(){return okmessages;}
public void setOkmessages(boolean m){okmessages=m;}
public boolean isNew() {return (this.id == null);}
}
And here is the createOrUpdatePhoneNumberForm.jsp:
<html lang="en">
<jsp:include page="../fragments/headTag.jsp"/>
<body>
<div class="container">
<jsp:include page="../fragments/bodyHeader.jsp"/>
<c:choose>
<c:when test="${phonenumber['new']}">
<c:set var="method" value="post"/>
</c:when>
<c:otherwise>
<c:set var="method" value="put"/>
</c:otherwise>
</c:choose>
<h2>
<c:if test="${phonenumber['new']}">New </c:if>
Phone Number
</h2>
<form:form modelAttribute="phonenumber" method="${method}" class="form-horizontal">
<div class="control-group" id="patient">
<label class="control-label">Patient </label>
<c:out value="${phonenumber.patient.firstName} ${phonenumber.patient.lastName}"/>
</div>
<petclinic:inputField label="PhoneNumber" name="number"/>
<div class="control-group">
<petclinic:selectField name="type" label="Type" names="${numtypes}" size="5"/>
</div>
Preferred number? <form:checkbox path="preferred"/><br>
OK to leave messages? <form:checkbox path="okmessages"/>
<td>
</td>
<div class="form-actions">
<c:choose>
<c:when test="${phonenumber['new']}">
<button type="submit">Add Phone Number</button>
</c:when>
<c:otherwise>
<button type="submit">Update Phone Number</button> <h3> Link to delete will go here.</h3>
</c:otherwise>
</c:choose>
</div>
</form:form>
<c:if test="${!phonenumber['new']}">
</c:if>
</div>
</body>
</html>
ClinicService.java is:
#Service
public class ClinicServiceImpl implements ClinicService {
private DocumentRepository documentRepository;
private PatientRepository patientRepository;
private AddressRepository addressRepository;
private PhoneNumberRepository phoneNumberRepository;
#Autowired
public ClinicServiceImpl(DocumentRepository documentRepository, PatientRepository patientRepository, AddressRepository addressRepository, PhoneNumberRepository phoneNumberRepository) {
this.documentRepository = documentRepository;
this.patientRepository = patientRepository;
this.addressRepository = addressRepository;
this.phoneNumberRepository = phoneNumberRepository;
}
#Override
#Transactional(readOnly = true)
public Collection<DocumentType> findDocumentTypes() throws DataAccessException {return documentRepository.findDocumentTypes();}
#Override
#Transactional(readOnly = true)
public Collection<Gender> findGenders() throws DataAccessException {return patientRepository.findGenders();}
#Override
#Transactional(readOnly = true)
public Collection<Race> findRaces() throws DataAccessException {return patientRepository.findRaces();}
#Override
#Transactional(readOnly = true)
public Patient findPatientById(int id) throws DataAccessException {return patientRepository.findById(id);}
#Override
#Transactional(readOnly = true)
public Collection<Patient> findPatientByLastName(String lastName) throws DataAccessException {return patientRepository.findByLastName(lastName);}
#Override
#Transactional
public void savePatient(Patient patient) throws DataAccessException {
System.out.println("-------------------------------------- inside clinicservice.savePatient()");
patientRepository.save(patient);}
#Override
#Transactional(readOnly = true)
public Document findDocumentById(int id) throws DataAccessException {
System.out.println("--------------- made it into clinicservice.findDocumentById() method");
return documentRepository.findById(id);}
#Override
#Transactional
public void saveDocument(Document doc) throws DataAccessException {documentRepository.save(doc);}
#Override
#Transactional
public void saveAddress(Address addr) throws DataAccessException {addressRepository.save(addr);}
#Override
#Transactional(readOnly=true)
public Address findAddressById(int id) throws DataAccessException {return addressRepository.findById(id);}
#Override
#Transactional(readOnly = true)
public Collection<State> findStates() throws DataAccessException {return addressRepository.findStates();}
#Override
#Transactional(readOnly = true)
public Collection<PhoneNumberType> findPhoneNumberTypes() throws DataAccessException {return phoneNumberRepository.findPhoneNumberTypes();}
#Override
#Transactional(readOnly = true)
public void savePhoneNumber(PhoneNumber pn) throws DataAccessException {
System.out.println("++++++++++++++++++++ inside savePhoneNumber(pn) : "+pn.getNumber()+" , "+pn.getType().getName());
phoneNumberRepository.save(pn);
}
#Override
#Transactional(readOnly=true)
public PhoneNumber findPhoneNumberById(int id) throws DataAccessException {return phoneNumberRepository.findById(id);}
}
JpaPhoneNumberRepository.java contains the following:
#PersistenceContext
private EntityManager em;
#Override
public void save(PhoneNumber phonenumber) {
System.out.println("------------------------------ inside save(phonenumber) : "+phonenumber.getNumber()+" , "+phonenumber.getType().getName());
if (phonenumber.getId() == null) {
System.out.println("phonenumber.getId() == null ");
this.em.persist(phonenumber);
}
else {
System.out.println("else");
this.em.merge(phonenumber);}
}
The correct new values for getNumber() and getType().getName() print out. And "else" prints out, but then the data is not updated in the database. Why not? (note that clinicservice calls this save() method of JpaPhoneNumberRepository.java.)
The problem is that you have ClinicServiceImpl > savePhoneNumber method annotated as #Transactional(readOnly = true). Change it to #Transactional
Why is the savePhoneNumber method in your ClinicService.java as #Transactional(readOnly=True)?
That is the cause of the problem