CRUD with Spring MVC - DRY Suggestions - java

I'm new to Spring MVC. I am writing a small app to learn. I am working on some basic CRUD. I am writing the same code more than once to edit/display a domain class. What would be a better/proper way to implement the edit and save method?
Thanks
The controller:
#RequestMapping(value="/userInfo/create/{id}")
public ModelAndView edit(#PathVariable Integer id, Model model)
{
logger.info("UserInfo edit {}", id);
UserInfo userInfo = userInfoService.get(id);
model.addAttribute("userInfo", userInfo);
model.addAttribute("parent" , userInfoService.get(userInfo.getParentId()));
model.addAttribute("allUsers", userInfoService.list());
model.addAttribute("affInfos", affInfoService.findAllByUserInfo(userInfo));
ModelAndView mv = new ModelAndView("userInfo/create", "command", model);
return mv;
}
#RequestMapping(value="/userInfo/save", method=RequestMethod.POST)
public ModelAndView save(#Valid #ModelAttribute("userInfo")UserInfo userInfo, BindingResult result, Model model)
{
logger.info("UserInfo save");
model.addAttribute("userInfo", userInfo);
model.addAttribute("parent" , userInfoService.get(userInfo.getParentId()));
model.addAttribute("allUsers", userInfoService.list());
model.addAttribute("affInfos", affInfoService.findAllByUserInfo(userInfo));
ModelAndView mv = new ModelAndView("userInfo/create", "command", model);
if(!result.hasErrors())
{
userInfoService.saveOrUpdate(userInfo);
model.addAttribute("flashMsg", "UserInfo saved!");
}
else
{
model.addAttribute("flashMsg", "Could not save.");
}
return mv;
}
The View:
<%#taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%#taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<html>
<head>
<title>Create/Edit UserInfo</title>
</head>
<body>
<div style="margin-left:100px;font-weight: bold;font-size:16px;margin-bottom:20px;margin-top: 10px;">User Information</div>
<c:if test="${flashMsg != null}">
<div>${flashMsg }</div>
</c:if>
<form:form modelAttribute="userInfo" action="${pageContext.request.contextPath}/userInfo/save" method="post" >
<form:hidden path="id"/>
<div style="width:200px;margin-left:100px;margin-bottom:10px;">
<div style="margin-bottom:4px;font-weight: bold;">Name</div>
<div><form:input path="name"/></div>
</div>
<div style="width:200px;margin-left:100px;margin-bottom:10px;">
<div style="margin-bottom:4px;font-weight: bold;">Parent</div>
<div>
<form:select path="parentId" itemLabel="name" itemValue="id" >
<form:option value="-1">Choose Parent</form:option>
<form:options items="${allUsers}" itemLabel="name" itemValue="id"/>
</form:select>
</div>
</div>
<c:if test="${affInfos != null }">
<div>
<table style="width:600px;border:1px solid #ccc;" class="center ui-corner-all shadow zebra-striped">
<thead>
<tr>
<th>Macro</th>
<th>AffID</th>
<th><button type="button" class="btn shadow">New</button></th>
</tr>
</thead>
<tbody>
<c:forEach var="affInfo" varStatus="i" items="${affInfos }">
<tr>
<td><input type="text" name="macro_${affInfo.id}" id="macro_${affInfo.id}" value="${affInfo.macro}"></td>
<td><input type="text" name="affid_${affInfo.id}" id="affid_${affInfo.id}" value="${affInfo.affid}"></td>
<td><button class="btn shadow" type="button">Delete</button></td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</c:if>
<div style="margin-left:100px;margin-top:10px;" >
<form:button class="btn shadow">Submit</form:button>
</div>
</form:form>
</body>
</html>

First you could of course create a method like this one :
private method init(){
model.addAttribute("userInfo", userInfo);
model.addAttribute("parent" , userInfoService.get(userInfo.getParentId()));
model.addAttribute("allUsers", userInfoService.list());
model.addAttribute("affInfos", affInfoService.findAllByUserInfo(userInfo));
}
But, if your controller is used for only one JSP page (JSPX is the recommend page type), you can use something like that for each attribute on your JSP Page :
#ModelAttribute("allUsers")
public List<User> populateUserInfoList() {
return userInfoService.list();
}
It will automatically add to the ModelAndView the attribute wich name is in the #ModelAttribute annotation. But be careful , this will be called each time you use your controller, wich could create useless called to the database if your controller do more than calling always the same kind of JSP which need the same data.
With this you don't need anymore this line :
model.addAttribute("allUsers", userInfoService.list());
Hope it helps you

Related

Spring MVC form radio input not updating model

I'm creating a web application using Spring MVC framework and forms.
I'm having trouble getting my form to update the field position in my PlayerModel. It simply doesn't save the value when I submit the form (check the controller inline comment on the submit() function).
If I select either radio button (with values 1 and 2) and submit, the model reaches the controller with value 0.
Despite having read countless similar questions/answers here on StackOverflow, I am unable to get this to work. What am I doing wrong here?
[EDIT]
I figured out the problem. For some reason, the value of the name attribute in the radio input is being used to match with the model attribute, instead of using path.
<input type="radio" id="index1" value="1" path="position" name="index" />
So it is trying to match index with the model, which of course does not exist, instead of using the position value in the path attribute.
Shouldn't it be the other way around?
playerView.jsp
<%# taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
</head>
<body>
<form:form action="/game/playerView" method="POST" modelAttribute="playerModel">
<table>
<tr>
<th>
<input type="radio" id="index1" value="1" path="position" name="index" />
<input type="radio" id="index2" value="2" path="position" name="index"/>
</th>
</tr>
<tr>
<td><input type="submit" value="Submit"/></td>
</tr>
</table>
</form:form>
</body>
</html>
GameController.java
#Controller
#SessionAttributes("playerModel")
public class GameController {
#RequestMapping(value = "playerView", method = RequestMethod.GET)
public ModelAndView hello(ModelMap map) {
PlayerModel playerModel = new PlayerModel();
playerModel.setPosition(0);
map.addAttribute("playerModel", playerModel);
return new ModelAndView("playerView", "playerModel", playerModel);
}
#RequestMapping(value = "playerView", method = RequestMethod.POST)
public ModelAndView submit(#ModelAttribute("playerModel") PlayerModel playerModel, BindingResult result, ModelMap model){
playerModel.getPosition(); // returns 0
model.addAttribute("playerModel", playerModel);
return new ModelAndView("playerView", "playerModel", playerModel);
}
}
PlayerModel.java
#Resource
public class PlayerModel {
private int position;
public int getPosition() {
return position;
}
public void setPosition(int position) {
this.position = position;
}
}
You are using Spring-MVC form tag therefore please do not use this <input type="radio" id="index1" value="1" path="position" name="index" /> insted of use like this (For more details)
<tr>
<td>Sex:</td>
<td>
Male: <form:radiobutton path="sex" value="M"/> <br/>
Female: <form:radiobutton path="sex" value="F"/>
</td>
</tr>
and there is no path variable in HTML <input type="radio"> ,
path should be used in the spring type declaration.
eg :
<form:input path="firstName"/> this code is changed to <input name="firstName" type="text"/> by Spring

spring return object on button click out of list

Hi guys hope you can help me, because i cant get further at the moment
I have my Controller.
#RequestMapping(value="/kundenseite", method= RequestMethod.GET)
public String kundenLogin(ModelMap model) {
if(kundeComponent.getKunde() != null) {
List<Restaurant> restaurants = restaurantService.alleRestaurants();
model.addAttribute("restaurants", restaurants);
return "kundenseite";
}else {
return "redirect:/kunde/login";
}
}
#RequestMapping(value="/kundenseite", method= RequestMethod.POST)
public String kundenLoginAnswer(ModelMap model, #ModelAttribute Restaurant restaurant) {
System.out.println(restaurant.toString());
return "kundenseite";
And my jsp file
<%# include file="common/header.jspf" %>
<div class="jumbotron text-center">
<h1>MiMiMi Lieferservice</h1>
<p>Der schnellste Lieferservice von Passpick</p>
</div>
<div style="margin-right:auto; margin-left:auto; width: 33%">
<h2 style="text-align: center">Restaurant wählen</h2>
<div class="well">
<c:forEach items="${restaurants}" var="restaurant">
<form:form modelAttribute="${restaurant}" method="post">
<div style="margin-top: 8px" class=col-sm-4 >${restaurant.name}</div>
<div style="margin-top: 8px" class=col-sm-4 >${restaurant.restaurantTyp}</div>
<button type="submit">Bestellen</button>
</form:form>
<br style="clear:both;" />
</c:forEach>
</div>
</div>
</body>
</html>
If the user presses a button i want to return a restaurant.
But i don't know how to make that happen, my thought was to use a form but i cant get it to send a complete restaurant object back
If there is no solution for this i have to write the id with the button.
You need input hidden inside the form tab as below input hidden:
<input type="hidden" name="name" value="${restaurant.name}">
<input type="hidden" name="restaurantTyp" value="${restaurant.restaurantTyp}">

Spring basic form error 405

Hi i got this error try to learn some of Spring Java framrework.
I got an 405 - Request method 'POST' not supported and i need some help to see what is my error on this
my controller
#Controller
#RequestMapping("overcomandant/addSitio.asp")
public class addSitioController {
#RequestMapping(method = RequestMethod.GET)
public ModelAndView addSitioForm() {
ModelAndView asf = new ModelAndView();
asf.setViewName("admin/addNewSite");
asf.addObject("sitio", new Sitio());
return asf;
}
#RequestMapping(value="admin/addNewSite", method = RequestMethod.POST)
public String addSitioSubmit(Sitio st, ModelMap model) {
model.addAttribute("url", st.getUrl());
model.addAttribute("nombre", st.getNombre());
model.addAttribute("estado", st.getEstado());
return "admin/exito";
}
#ModelAttribute("estadoLista")
public Map<String,String> ListadoEstados() {
Map<String, String> estado = new LinkedHashMap<>();
estado.put("1","Activo");
estado.put("2","Inactivo");
estado.put("3","Testing");
return estado;
}
}
and this is my form addNewSite.jsp
<form:form method="POST" commandName="sitio">
<div class="form-group">
<form:label path="id">ID</form:label>
<form:input path="id" cssClass="form-control"/>
</div>
<div class="form-group">
<form:label path="url">URL</form:label>
<form:input path="url" cssClass="form-control"/>
</div>
<div class="form-group">
<form:label path="nombre">Nombre</form:label>
<form:input path="nombre" cssClass="form-control"/>
</div>
<div class="form-group">
<form:label path="estado">Estado</form:label>
<form:select path="estado" cssClass="form-control">
<form:option value="0">Seleccione</form:option>
<form:options items="${estadoLista}" />
</form:select>
</div>
<input type="submit" value="Enviar" class="btn btn-primary" />
</form:form>
and the exito.js
<%#taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%#page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JSP Page</title>
</head>
<body>
<h1>Hello World!</h1>
<p><c:out value="${url}"></c:out></p>
</body>
</html>
I try to understand what is worng.
The controller creates an object site adding the info form the form an then the otrer .jsp renders the new object created...
You have to specify your form action to correspond the method in your controller : admin/addNewSite.
The 405 error tells you that the form action is unknown.

Spring MVC - Charset breaking when I submit my form

SOLUTION: I've changed the server from tomcat to jetty and the charset is back to normal
I'm having some trouble with the enconding on a application. Everytime I save something to the database the encoding breaks, but for reading is ok (I tested by changing manually on the db).
As Ralph asked I've checked if the charset is broke before I save on the database, and it's. So I'm changing the question to reflect better the problem.
I'm using Spring MVC, Hibernate and MySQL. I've configurated spring to use UTF-8 in my configuration class:
public class ServletSpringMVC extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { AppWebConfiguration.class, JPAConfiguration.class, SecurityConfiguration.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] {};
}
#Override
protected String[] getServletMappings() {
return new String[] {"/"};
}
#Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
encodingFilter.setEncoding("UTF-8");
encodingFilter.setForceEncoding(true);
return new Filter[] {encodingFilter};
}
#Override
protected void customizeRegistration(ServletRegistration.Dynamic registration) {
registration.setMultipartConfig(new MultipartConfigElement(""));
}
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
super.onStartup(servletContext);
servletContext.addListener(RequestContextListener.class);
servletContext.setInitParameter("spring.profiles.active", "dev");
}
}
My JSP is:
<%# page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<%# taglib prefix="tags" tagdir="/WEB-INF/tags" %>
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%# taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<tags:template title="Jobs">
<jsp:attribute name="bodyArea">
<div class="container">
<c:if test="${not empty jobId}">
<c:url var="urlAction" value="${spring:mvcUrl('JC#updateJob').arg(0,jobId).build()}"/>
</c:if>
<c:if test="${empty jobId}">
<c:url var="urlAction" value="${spring:mvcUrl('JC#addJob').build()}"/>
</c:if>
<form:form action="${urlAction}" method="post" modelAttribute="jobDTO" id="form" acceptCharset="utf-8">
<input type="hidden" name="board" value="${boardId}">
<div class="form-group">
<label> <spring:message code="job.form.client"/> </label>
<form:input path="client" cssClass="form-control"/>
<form:errors path="client"/>
</div>
<div class="form-group">
<label> <spring:message code="job.form.priority"/> </label>
<form:select path="priority" cssClass="form-control">
<form:option value="" label=""/>
<form:options items="${priorities}"/>
</form:select>
<form:errors path="priority"/>
</div>
<div class="form-group">
<label> <spring:message code="job.form.status"/> </label>
<form:select path="status" cssClass="form-control">
<form:option value="" label=""/>
<form:options items="${statuses}"/>
</form:select>
<form:errors path="status"/>
</div>
<div class="form-group">
<label> <spring:message code="job.form.responsible"/> </label>
<form:select path="responsible" cssClass="form-control">
<form:option value="" label=""/>
<form:options items="${boardHelper.getBoardUsers(boardId)}"/>
</form:select>
<form:errors path="responsible"/>
</div>
<div class="form-group">
<label> <spring:message code="job.form.description"/> </label>
<form:textarea path="description" cssClass="form-control" rows="5"/>
<form:errors path="description"/>
</div>
</form:form>
<div class="container">
<div class="row">
<div class="col-lg-1">
<button type="submit" class="btn btn-success" form="form">
<span class="glyphicon glyphicon-floppy-disk"></span>
<spring:message code="Save"/>
</button>
</div>
<c:if test="${not empty jobId}">
<div class="col-lg-1">
<form action="${spring:mvcUrl('JC#deleteJob').arg(0,jobId).build()}" method="post">
<button type="submit" class="btn btn-danger">
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
<span class="glyphicon glyphicon-trash"></span>
<spring:message code="Delete"/>
</button>
</form>
</div>
</c:if>
</div>
</div>
</div>
</jsp:attribute>
</tags:template>

Spring: Request method 'POST' not supported

Browsed the forum but didn't find solution which can solve my problem. There are 2 pages: index.jsp - start page which includes form to be populated and the list of results; edit.jsp - allows to edit data of any row from the list of results provided by index.jsp.
When I fill in the form all the data subbmitted successfully, when I try to edit any row in the list of results I redirected to edit.jsp but if I submit the changes an exception is thrown: HTTP Status 405 - Request method 'POST' not supported. I would appreciate any idea how to treat the issue.
index.jsp
<%# page contentType="text/html;charset=UTF-8" language="java" %>
<%#taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%#taglib prefix="s" uri="http://www.springframework.org/tags" %>
<%#taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<title></title>
</head>
<body>
<form:form method="post" action="add" modelAttribute="account">
<table>
<tr>
<td><form:label path="number">Number</form:label></td>
<td><form:input path="number"/></td>
</tr>
<tr>
<td><form:label path="amount">Amount</form:label></td>
<td><form:input path="amount"/></td>
</tr>
<tr>
<td><form:label path="currency">Currency</form:label></td>
<td><form:input path="currency"/></td>
</tr>
<tr>
<td><form:label path="date">Date</form:label></td>
<td><form:input path="date" type="date"/>
</tr>
</table>
<input type="submit" value="Submit"/>
</form:form>
<table>
<tr border="1">
<td>Number</td>
<td>Amount</td>
<td>Currency</td>
<td>Date</td>
</tr>
<c:forEach items="${listOfAccounts}" var="items">
<tr border="1">
<td>${items.number}</td>
<td>${items.amount}</td>
<td>${items.currency}</td>
<td>${items.date}</td>
<td>edit</td>
</tr>
</c:forEach>
</body>
</html>
edit.jsp
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%# page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Edit Account</title>
</head>
<body>
<form:form modelAttribute="account" method="post" action="edited">
<form:hidden path="id" value="${account.id}"></form:hidden>
<form:label path="number">Number</form:label>
<form:input path="number" value="${account.number}"/><br>
<form:label path="amount">Amount</form:label>
<form:input path="amount" value="${account.amount}"/><br>
<form:label path="currency">Currency</form:label>
<form:input path="currency" value="${account.currency}"/><br>
<form:label path="date">Date</form:label>
<form:input path="date" type="date" value="${account.date}"/>
<input type="submit" value="Submit"/>
</form:form>
</body>
</html>
Controller.java
#Controller
public class AccountController {
#Autowired
private AccountService accountService;
private Account account;
#RequestMapping(value="/", method = RequestMethod.GET)
public String welcomeMethod(ModelMap map) {
Account account = new Account();
map.addAttribute("account", account);
map.addAttribute("listOfAccounts", accountService.getListOfAccounts());
return "index";
}
#RequestMapping(value="add", method = RequestMethod.POST)
public String addAccount(#ModelAttribute(value="account") Account account, ModelMap map) {
accountService.addAccount(account);
map.addAttribute("listOfAccounts", accountService.getListOfAccounts());
return "index";
}
#RequestMapping(value="edit/{id}", method = RequestMethod.GET)
public String editAccount(#PathVariable("id") int id, ModelMap model) {
Account account = accountService.getAccountById(id);
model.addAttribute("account", account);
return "edit";
}
#RequestMapping(value="edited", method = RequestMethod.POST)
public String updateAccount(#ModelAttribute(value="account") Account account, ModelMap map) {
accountService.updateAccount(account);
map.addAttribute("listOfAccounts", accountService.getListOfAccounts());
return "index";
}
}
Your problem is that you are using relative mappings in your form, when you click on edit, your URL becomes /edit/{someid} and your edit.jsp form is loaded. When you edit the data and click submit, your URL will become /edit/{someid}/edited, the mapping will match the /edit/{someid} handler method witch is using a GET method and that is why you get your error.
To solve it, in your edit.jsp simple add a backslash to action, action="/edited"
Hope it helps

Categories