Spring receive data from the client - spring

Good evening!
public class Order {
private int idOrder;
private Basket basket;
// getter and setter
}
public class AnonymousOrder {
private String name;
private String telephone;
// getter and setter
}
public class UserOrder {
private User user;
// getter and setter
}
public class OrdersForm {
private List< ? extends Order> orders;
// getter and setter
}
#RequestMapping(value="/showOrders")
public String showOrders(Model model){
List<? extends Order> orders= adminManager.searchAllOrders();
OrdersShowForm ordersForm = new OrdersShowForm();
ordersForm.setOrders(orders);
model.addAttribute("ordersForm", ordersForm);
return "showOrders";
}
#RequestMapping(value="/showOrders", method = RequestMethod.POST)
public String showOrdersPOST(#ModelAttribute("ordersForm") OrdersShowForm ordersForm){
System.out.print(ordersForm);
return "showOrders";
}
<form:form modelAttribute="ordersForm">
<table class="features-table" border="1">
<c:forEach items="${ordersForm.orders}" var="order" varStatus="status">
<tr>
<c:if test="${order['class'].simpleName != 'UserOrder'}">
<td>
<input name="orders[${status.index}].name" value="${order.name}"/>
</td>
</c:if>
</c:forEach>
</table>
Problem: I am passing on page two types of data: UserOrder and AnonymousOrder, but when I try to get them on the server then come data type Order.
Question: How to transfer data to the server without changing their actual type?
P.S. sorry for my English)

Related

EL1008E: Property or field 'applicationName' cannot be found on object of type 'java.lang.String' - maybe not public or not valid?

Been stuck with this error for a while now.
EL1008E: Property or field 'applicationName' cannot be found on object of type 'java.lang.String' - maybe not public or not valid?
I'm trying to get the records from database through thymeleaf, but always gets this error. I think I've declared everything that is needed this.
Here's my code
Model
#Entity
#Table(name = "sms_alert", schema = "public")
public class SmsAlert {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "sms_id")
private Long smsId;
#Column(name = "application_name")
private String applicationName;
#Column(name = "sms_flag")
private String smsFlag;
public SmsAlert() {
}
public SmsAlert(String applicationName, String smsFlag) {
super();
this.applicationName = applicationName;
this.smsFlag = smsFlag;
}
public Long getSmsId() {
return smsId;
}
public void setSmsId(Long smsId) {
this.smsId = smsId;
}
public String getApplicationName() {
return applicationName;
}
public void setApplicationName(String applicationName) {
this.applicationName = applicationName;
}
public String getSmsFlag() {
return smsFlag;
}
public void setSmsFlag(String smsFlag) {
this.smsFlag = smsFlag;
}
}
Controller
#GetMapping(value = "/smsAlert/{applicationName}")
public String viewApplicationSmsAlert(#PathVariable("applicationName") String applicationName, Model model) {
System.out.println(applicationName);
model.addAttribute("sms", smsService.findSmsFlagByAppName(applicationName));
return "test";
}
Repository
#Repository
public interface SmsRepository extends JpaRepository<SmsAlert, Long> {
#Query(value = "SELECT s.application_name, s.sms_flag FROM public.sms_alert s WHERE s.application_name= :applicationName ", nativeQuery = true)
public String findSmsFlagByAppName(#Param("applicationName") String applicationName);
Service
#Service
public class SmsService {
#Autowired
private SmsRepository smsRepository;
public List<SmsAlert> findAll() {
return smsRepository.findAll();
}
public String findSmsFlagByAppName(String applicationName) {
return smsRepository.findSmsFlagByAppName(applicationName);
}
public void updateSmsFlag(String applicationName, String smsFlag) {
smsRepository.updateSmsFlag(applicationName, smsFlag);
}
}
HTML File
<body>
<div id="content">
<div>
<table class="table table-hover table-striped" id="invTable">
<thead>
<tr class="table-primary">
<th id="terminalId">Terminal ID</th>
</tr>
</thead>
<tbody>
<tr th:each="sms : ${sms}">
<td th:text="${sms.applicationName}"></td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
The findSmsFlagByAppName method in SmsRepository returns a String. Your controller is putting that String in the model with the variable name sms. Then in your view you are referencing ${sms.applicationName} which is trying to evaluate the applicationName property on that String, which of course does not exist.
You could make the error go away a number of ways. One is, populate the model withe applicationName as a String and then in the view simply refer to that String.
Another option is to rework the findSmsFlagByAppName method to return a SmsAlert.

Sping MVC and hibernate: undeclared variable in jsp become null when saved

I just created my simple web application using Spring frameworks and hibernate. But I face the crucial problem when there is a transaction with my database.
When I tried to update my object, undeclared variables become null when saved to the database.
I will explain it with an example.
Model.java:
public class Model implements Serializable {
private int id;
private String firstName;
private String lastName;
private String description;
//setter getter
}
ModelDaoImpl.java:
#Repository("modelDao")
public class ModelDaoImpl implements ModelDao {
#Autowired
SessionFactory sessionFactory;
public Model create (Model model) throws Exception {
this.sessionFactory.getCurrentSession().save(model);
return model;
}
public Model update (Model model) throws Exception {
this.sessionFactory.getCurrentSession().update(model);
return model;
}
public Model get (Serializable id) throws Exception {
return (Model) this.sessionFactory.getCurrentSession().get(Model.class, id);
}
}
ModelServiceImpl.java:
#Service("modelService")
public class ModelServiceImpl implements ModelService {
#Autowired
modelDao modelDao;
#Transactional
public Model create (Model model) throws Exception {
return modelDao.create(model);
}
#Transactional
public Model update (Model model) throws Exception {
return modelDao.udpdate(model);
}
#Transactional
public Model get (Serializable id) throws Exception {
return modelDao.get(id);
}
}
ModelController.java:
#Controller
public class ModelController {
#Autowired
ModelService modelService
#RequestMapping(value="/editModel", method.RequestMethod.GET)
public String formCreator(ModelMap model, HttpServletRequest request) {
Integer id = new Integer(request.getParameter("id"));
Model modelData = new Model();
if (id != null) {
modelData = modelService.get(id);
}
model.addAttribute("modelData", modelData);
return "editModel"
}
#RequestMapping(value="/saveModel", method.RequestMethod.POST)
public String saveData(#ModelAttribute("modelData") Model modelData) {
if (modelData.getId() == null) {
modelService.create(modelData);
} else {
modelService.update(modelData);
}
return "redirect:/modelList";
}
//SKIP FOR GET MODEL LIST AND GET MODEL DETAIL
}
editModel.jsp:
<form:form action="${pageContext.request.contextPath}/saveModel" method="POST" modelAttribute="modelData">
<table>
<form:hidden path="id"/>
<tr>
<td>First Name:</td>
<td><form:input path="firstName"/></td>
</tr>
<tr>
<td>Last Name:</td>
<td><form:input path="lastName"/></td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="Save"></td>
</tr>
</table>
</form:form>
From jsp page we see that I didn't declare variable 'description', but when update my existing data the variable 'description' become null. I have tried using #DynamicUpdate or related to dynamic update process, but the result was still the same, the variable 'description' still become null.
Any suggestion?
The problem is that the way your controller is written: a new Model instance is created
and populated on execution of saveData.
You can update your code to be like the below. Now on POST the Model instance
will be that returned from getModel() rather than a new instance and only the
values specified in the incoming request wil be updated. We can also update the GET to use the same code to populate the model.
Essentially then:
on GET - the model will be populated for the UI by a call to #ModelAttribute
on POST - the model will be populated and the Model instance returned will be passed to saveData();
See:
https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-modelattrib-method-args
#Controller
public class ModelController {
#Autowired
ModelService modelService
#RequestMapping(value="/editModel", method.RequestMethod.GET)
public String formCreator(HttpServletRequest request) {
return "editModel"
}
#RequestMapping(value="/saveModel", method.RequestMethod.POST)
public String saveData(#ModelAttribute("modelData") Model model) {
//you can have 1 method in your service and DAO
//DAO can use saveOrUpdate() method of session;
modelService.persist(model);
return "redirect:/modelList";
}
#ModelAttribute("modelData")
public Model getModel(#RequestParam(name = "id", required = false)Integer id){
return id != null ? modelService.get(id) : new Model();
}
}

Springboot and thymealf loop

hope you can help with this simple noob problem. I creating a Multiple choice question using springboot and thymeleaf.I am getting this error and hope you can help me write the controller method.
Error during execution of processor 'org.thymeleaf.spring4.processor.attr.SpringInputGeneralFieldAttrProcessor' (learning:23)
Neither BindingResult nor plain target object for bean name 'options[0]' available as request attribute
<form method="post" th:action="#{/list}" >
<table>
<tr th:each="option, rowStat : *{a}">
<td><input type="radio" th:field="*{options[__${rowStat.index}__].ansA}" th:value="A"/></td>
<td><input type="radio" th:field="*{options[__${rowStat.index}__].ansB}" th:value="B"/></td>
</tr>
</table>
<input type="submit" value="ok"/>
</form>
Model object
#Entity
public class LearningStyle {
private int Qid;
private String question;
private String ansA;
private String ansB;
public LearningStyle(int qid, String question, String ansA, String ansB) {
Qid = qid;
this.question = question;
this.ansA = ansA;
this.ansB = ansB;
}
public LearningStyle(){}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "Qid", nullable = false, updatable = false)
public int getQid() {
return Qid;
}
public void setQid(int qid) {
Qid = qid;
}
public String getQuestion() {
return question;
}
public void setQuestion(String question) {
this.question = question;
}
public String getAnsA() {
return ansA;
}
public void setAnsA(String ansA) {
this.ansA = ansA;
}
public String getAnsB() {
return ansB;
}
public void setAnsB(String ansB) {
this.ansB = ansB;
}
}
Controller
public class LearningStyleController {
#Autowired
LearningStyleService learningstyleservice;
#RequestMapping("/list")
public String learningstyle(Model model) {
List<LearningStyle> a= learningstyleservice.findAll();
model.addAttribute("a",a);
return "learning";
}
#RequestMapping(value = "/list", method = RequestMethod.POST)
public String learn(#ModelAttribute("a") LearningStyle learningStyle, Model model) {
//code to get list of object
return "home";
}

How to bind Spring form:checkbox instead of form:checkboxes?

I am having problems with form:checkbox. I cannot make it display selected values. When I selected values and submit, correct values are display in database. When I load page all values (checkboxes) are not selected.
Elements below are located inside this:
<form:form role="form" commandName="user" class="form-horizontal" action="${form_url}">
</form:form>
This works just fine:
<form:checkboxes items="${availableRoles}" path="roles" itemLabel="role" itemValue="id" element="div class='checkbox'"/>
This doesn't work:
<c:forEach items="${availableRoles}" var="r" varStatus="status">
<div class="checkbox">
<form:checkbox path="roles" label="${r.description}" value="${r.id}"/>
</div>
</c:forEach>
This is my domain class:
public class User {
private List<Role> roles;
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
This is my custom property editor:
public class RolePropertyEditor extends PropertyEditorSupport {
#Override
public void setAsText(String text) {
Role role = new Role();
role.setId(Integer.valueOf(text));
setValue(role);
}
}
Controller has this method:
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(Role.class, new RolePropertyEditor());
}
Controller method:
#RequestMapping(value = "/update/{userId}", method = RequestMethod.GET)
public String updateUser(#PathVariable Integer userId, Model model) {
User user = userService.getByUserId(userId);
List<Role> availableRoles = roleService.getAllRoles();
model.addAttribute("availableRoles", availableRoles);
model.addAttribute("user", user);
return "user/update";
}
After debugging session I found the solution.
Because of Spring internals JSP should look like this:
<c:forEach items="${availableRoles}" var="r">
<div class="checkbox">
<form:checkbox path="roles" label="${r.description}" value="${r}" />
</div>
</c:forEach>
Notice that value is item (r), not item's member like r.id.
Also you need getAsText implementation in your custom PropertyEditor.
#Override
public String getAsText() {
Role role = (Role) this.getValue();
return role.getId().toString();
}

Stripes: I can pre-populate a form, but after submit the formBean is null

I can pre-populate my Stripes JSP form with an object, client in my case, but when I submit this form, my object is returning as null.
I have created a second "temp" object that is a parallel duplicate of client and this retains its values, so I can't see an issue passing an object in the request
My form is as follows :
<s:form beanclass="com.jameselsey.salestracker.action.ViewClientAction">
<s:hidden name="clientA" value="${actionBean.clientA}"/>
<s:hidden name="clientId" value="${actionBean.clientId}"/>
<table>
<tr>
<td>Name : </td>
<td><s:text name="client.name"/></td>
</tr>
<tr>
<td>Sector : </td>
<td><s:text name="client.sector"/></td>
</tr>
<!-- omitted some attirbutes, not needed here -->
</table>
</s:form>
My action looks like
public class ViewClientAction extends BaseAction
{
#SpringBean
ClientService clientService;// = new ClientService();
private Integer clientId;
private Client client;
private Client clientA;
public void setClient(Client client)
{
this.client = client;
}
public Integer getClientId()
{
return clientId;
}
public void setClientId(Integer clientId)
{
this.clientId = clientId;
}
public Client getClientA()
{
return clientA;
}
public void setClientA(Client clientA)
{
this.clientA = clientA;
}
public Client getClient()
{
return client;
}
#DefaultHandler
public Resolution quickView()
{
clientA = clientService.getClientById(clientId);
client = clientService.getClientById(clientId);
return new ForwardResolution("/jsp/viewClientQuickView.jsp");
}
public Resolution save()
{
clientService.persistClient(client);
return new ForwardResolution("/jsp/reports.jsp");
}
public Resolution viewClientInfo()
{
client = clientService.getClientById(clientId);
return new ForwardResolution("/jsp/viewClientClientInfo.jsp");
}
...
If I set a breakpoint at clientService.persistClient(client); I can see that ClientA has all of the original values of the object, yet client is nulled.
Have I missed something that binds the form bean to the client object in my action?
Thanks
Add this line in your JSP:
<s:hidden name="client" value="${actionBean.client}"/>
I got this scenario working by adding a #Before method to re-hydrate the nested object. After this, save works properly
#Before(stages = LifecycleStage.BindingAndValidation)
public void rehydrate() {
if (context.getRequest().getParameter("save")!=null){
this.domainObject = getHibernateSession().load(DomainObject.class, context.getRequest().getParameter("id"));
}
}
public void save(){
Session session=getHibernateSession();
session.update(domainObject);
session.commit();
//...
}

Resources