Spring Boot Adding Model to the View with Thymeleaf and MVC - spring-boot

Ok, so I'm trying to put an attribute of an object from the model to the view as a list using thymeleaf, spring boot and jpa, I've been reading over the code for hours and I can't seem to spot my problem, also in the same application I have a very similar function working so I sort of know how to do it, but I just cannot seem to figure out this one. I keep getting an error Property or field 'question' cannot be found on null. I have no idea where I'm going wrong. The object I'm have is called QuestionAnswerSet, and I have a question string and an answer string in the database, that I can submit through the app, so it's not a problem with the database. Also everything is good with my pom file because as I said earlier I have done a very similar function.
Here's my controller.
#Controller
public class QuestionAnswerSetController
{
private QuestionAnswerSetRepository questionAnswerSetRepo;
#RequestMapping("sets")
public String sets (ModelMap model)
{
List<QuestionAnswerSet> questionAnswerSets = questionAnswerSetRepo.findAll();
model.put("questionAnswerSets", questionAnswerSets);
return "sets";
}
#RequestMapping(value="editSet/{questionAnswerSetId}", method=RequestMethod.GET)
public String editSetGet (#PathVariable Long questionAnswerSetId, ModelMap model)
{
return "editCourse";
}
#RequestMapping(value="createSet", method=RequestMethod.GET)
public String createSetGet (ModelMap model)
{
QuestionAnswerSet questionAnswerSet = new QuestionAnswerSet();
model.put("questionAnswerSet", questionAnswerSet);
return "createSet";
}
#RequestMapping(value="createSet", method=RequestMethod.POST)
public String createSetPost (#ModelAttribute QuestionAnswerSet questionAnswerSet, ModelMap model)
{
questionAnswerSetRepo.save(questionAnswerSet);
return "redirect:/sets";
}
#Autowired
public void setQuestionAnserSetRepo(QuestionAnswerSetRepository questionAnserSetRepo) {
this.questionAnswerSetRepo = questionAnserSetRepo;
}
}
Here's my html
<div th:each="Set : ${questionAnswerSets}" th:object="${questionAnswerSet}">
<span th:text="${questionAnswerSet.question}"></span>
</div>
<div th:if="${#lists.isEmpty(questionAnswerSets)}">
There is no sets to display.
</div>
Here's my repository, it's pretty standard, just though I would include it
public interface QuestionAnswerSetRepository extends JpaRepository<QuestionAnswerSet, Long> {
}
And here's my QuestionAnswerSet.java object, which is what I'm trying to return as a list
#Entity
public class QuestionAnswerSet {
private Long id;
private String question;
private String answer;
private User user;
#Id
#GeneratedValue
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getQuestion() {
return question;
}
public void setQuestion(String question) {
this.question = question;
}
public String getAnswer() {
return answer;
}
public void setAnswer(String answer) {
this.answer = answer;
}
#ManyToOne
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
And Here's the error in my console
org.springframework.expression.spel.SpelEvaluationException: EL1007E:(pos 0): Property or field 'question' cannot be found on null

Yup, that should be pretty straightforward, here is the exception :
Property or field 'question' cannot be found on null
Spring EL tries to evaluate the below :
<div th:each="Set : ${questionAnswerSets}" th:object="${questionAnswerSet}">
<span th:text="${questionAnswerSet.question}"></span>
</div>
And it is unable to find questionAnswerSet ,which is null hence the error.
Use something like this :
<div th:each="questionAnswerSet : ${questionAnswerSets}">
<span th:text="${questionAnswerSet.question}"></span>
</div>
Refer Doc :
http://www.thymeleaf.org/doc/tutorials/2.1/usingthymeleaf.html#using-theach

Related

Spring Data JPA JpaRepository only uses No Arg Constructor

I have this simple REST API that i created with Spring Boot.
In this app, I have a a POJO called Expense with 4 fields. I have a no Argument constructor and another constructor that takes only two inputs. One String value "item" and one Integer value "amount". The date is set using the LocalData.now() method and the id is set automatically in a MySql db running in the server.
Here's my Entity class
#Entity
public class Expense {
#Id
#GeneratedValue (strategy = GenerationType.AUTO)
private Integer id;
private String date;
private String item;
private Integer amount;
//No Arg Construction required by JPA
public Expense() {
}
public Expense(String item, Integer amount) {
this.date = LocalDate.now().toString();
this.item = item;
this.amount = amount;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getItem() {
return item;
}
public void setItem(String item) {
this.item = item;
}
public Integer getAmount() {
return amount;
}
public void setAmount(Integer amount) {
this.amount = amount;
}
}
I have another class with RestController annotation where i have set a method to post Expense object with a post method using Request Mapping annotation.
#RestController
public class ExpController {
private ExpService expService;
private ExpenseRepo expenseRepo;
#Autowired
public ExpController(ExpService expService, ExpenseRepo expenseRepo) {
this.expService = expService;
this.expenseRepo = expenseRepo;
}
#RequestMapping(path = "/addExp", method=RequestMethod.POST)
public void addExp(Expense expense){
expenseRepo.save(expense);
}
}
Now finally i am using PostMan to make the HTTP Post Request. I have made a simple Json Format text to send Item and Amount
{
"item":"Bread",
"amount": 75
}
After I make the post request, all i can see is that a new Entry is created but all values are set to null.
I have done some experimentation and found out that the expenseRepo.save(expense) method is only using the default no Arg constructor to save the data. But it's not using the second constructor that takes the two parameters that I am passing through Postman
How to solve this issue. Please help
Change your controller method like this
#RequestMapping(path = "/addExp", method=RequestMethod.POST)
public void addExp(#RequestBody Expense expense){
expenseRepo.save(expense);
}
You need to use #RequestBody

Spring framework - Data not display in view page

no errors display in my view...but when it run it gives the value as '0'. my database table name is 'categories'.it has a value like 'category_l dummy' for the column .But in the view display as a 0...please help me to slove this...
This is my model class
#Entity
#Table(name = "categories")
public class CategoriesModel implements Serializable{
#Id
#Column
#GeneratedValue(strategy = GenerationType.AUTO) //for autonumber
private int id;
#Column
private String category1;
#Column
private String desccategory1;
public CategoriesModel() {
}
public CategoriesModel(
int id,
String category1, String desccategory1) {
super();
this.id = id;
this.category1 = category1;
this.desccategory1 = desccategory1;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCategory1() {
return category1;
}
public void setCategory1(String category1) {
this.category1 = category1;
}
public String getDesccategory1() {
return desccategory1;
}
public void setDesccategory1(String desccategory1) {
this.desccategory1 = desccategory1;
}
This is my Dao class
public interface CategoriesDao {
public void add(CategoriesModel categories);
public void edit(CategoriesModel categories);
public void delete(int id);
public CategoriesModel getCategoriesModel(int id);
public List getAllCategoriesModel();
}
This is my Dao impl class
#Repository
public class CategoriesDaoImpl implements CategoriesDao {
#Autowired
private SessionFactory session;
#Override
public void add(CategoriesModel categories) {
session.getCurrentSession().save(categories);
//this "categories" is a table name
}
#Override
public void edit(CategoriesModel categories) {
session.getCurrentSession().update(categories);
//this "categories" is a table name
}
#Override
public void delete(int id) {
session.getCurrentSession().delete(getCategoriesModel(id));
//this "id" is a feild in Model
}
#Override
public CategoriesModel getCategoriesModel(int id) {
return (CategoriesModel) session.getCurrentSession().get(CategoriesModel.class, id);
}
#Override
public List getAllCategoriesModel() {
return session.getCurrentSession().createQuery("from CategoriesModel").list();
//this "CategoriesModel" is a its model name
}
This is my service class
public void add(CategoriesModel categories);
public void edit(CategoriesModel categories);
public void delete(int id);
public CategoriesModel getCategoriesModel(int id);
public List getAllCategoriesModel();
This is my service impl class
#Service
public class CategoriesServiceImpl implements CategoriesService {
#Autowired
private CategoriesDao CategoriesDao;
#Transactional
public void add(CategoriesModel categories) {
CategoriesDao.add(categories);
}
#Transactional
public void edit(CategoriesModel categories) {
CategoriesDao.edit(categories);
}
#Transactional
public void delete(int id) {
CategoriesDao.delete(id);
}
#Transactional
public CategoriesModel getCategoriesModel(int id) {
return CategoriesDao.getCategoriesModel(id);
}
#Transactional
public List getAllCategoriesModel() {
return CategoriesDao.getAllCategoriesModel();
}
this is my controller class
#Autowired
private CategoriesService CategoriesService;
#RequestMapping("/")
public String setupForm(Map<String, Object> map) {
CategoriesModel categories = new CategoriesModel();
//Create a new object from details Model
map.put("category", categories);
//new created object is assign and view name
map.put("categoriesList", CategoriesService.getAllCategoriesModel());
//view feild assign list in view page
System.out.println(categories);
return "allcategories";
//return page(view name)
}
this is my view
<c:forEach items="${categoriesList}" var="category">
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
<div id="category">
<div class="col-lg-2 col-md-2 col-sm-4 col-xs-6 ">
<a href="" target="_self"><img src="images/properties/cars.png" class="img-responsive">
<div class="link">
<p>${category.category1}</p>
</div>
</div>
#Autowired
private CategoriesService CategoriesService;
#RequestMapping("/")
public String setupForm(Model model) {
CategoriesModel categories = new CategoriesModel();
//Create a new object from details Model
model.addAttribute("category", categories);
//new created object is assign and view name
model.addAttribute("categoriesList", CategoriesService.getAllCategoriesModel());
//view feild assign list in view page
System.out.println(categories);
return "allcategories";
//return page(view name)
}

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";
}

Update database ManytoOne relationship (Spring Boot + MVC +Thymeleaf)

I have two entity class.one is PhaseEntity and another is TaskEntity. PhaseId will be the foreign key of TaskEntity class. I can create and save the value to the database but cannot update the database.
Portion of TaskEntity class:
#ManyToOne(optional=false)
#JoinColumn(name="phaseId")
private PhaseEntity phaseEntity;
Controller class:
public class TaskController {
#Autowired
private TaskService taskService;
#Autowired
private PhaseService phaseService;
#RequestMapping(value="/task/create",method=RequestMethod.GET)
public String createForm(Model model,Principal principal){
model.addAttribute(new TaskEntity());
model.addAttribute("body", "task/task-create");
model.addAttribute("generaltaskDto",new GeneralTaskDto());
model.addAttribute("phaseEntities", phaseService.phaseList());
return "layouts/default";
}
#RequestMapping(value="/task/create",method=RequestMethod.POST)
public String createFormPost(Model model,GeneralTaskDto generaltaskDto,BindingResult result){
TaskEntity taskAndPhase=generaltaskDto.getTaskEntity();
taskAndPhase.setPhaseEntity(phaseService.getPhaseByPhaseId(generaltaskDto.getPhaseId()));
taskService.saveTask(taskAndPhase);
return "redirect:/task/list";
}
#GetMapping(value="/task/update/{id}")
public String updateTask(Model model,#PathVariable String id){
TaskEntity taskEntity= taskService.getTaskId(Integer.parseInt(id));
model.addAttribute("body", "task/task-create");
model.addAttribute("phaseEntities", phaseService.phaseList());
return "layouts/default";
}
GeneraltaskDto class:
public class GeneralTaskDto {
private TaskEntity taskEntity=new TaskEntity();
private Integer phaseId;
public TaskEntity getTaskEntity() {
return taskEntity;
}
public void setTaskEntity(TaskEntity taskEntity) {
this.taskEntity = taskEntity;
}
public Integer getPhaseId() {
return phaseId;
}
public void setPhaseId(Integer phaseId) {
this.phaseId = phaseId;
}
}
here is the client page of the application
can anyone help plz how to update the database with controller request. Thanks in advance.
Please try adding these lines in your controller under updateTask method after TaskEntity taskEntity= taskService.getTaskId(Integer.parseInt(id)); line.
PhaseEntity phaseEntity=taskEntity.getPhaseEntity();
generaltaskDto.setTaskEntity(taskEntity);
generaltaskDto.setPhaseId(phaseEntity.getPhaseId());
model.addAttribute("generaltaskDto", generaltaskDto);

Model Attributes null with Thymeleaf-spring boot

I have a weird error that is driving me crazy.
I have a Controller with two different Get Methods - for two different url mappings.
URL1 works perfectly fine, with URL2, I get
[THYMELEAF][http-nio-8080-exec-3] Exception processing template
"questionnaireForm": Error during execution of processor
'org.thymeleaf.standard.processor.attr.StandardEachAttrProcessor'
(questionnaireForm:10)
caused by
java.lang.NullPointerException: null at org.thymeleaf.context.WebSessionVariablesMap.hashCode(WebSessionVariablesMap.java:276) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE]
After hours of checking each line, it's clear that my Controller Get Method is adding a non-null object to the Model.addAttribute before calling the view.
I've also removed all of my code from the template and just added the following to troubleshoot:
<tr th:each="var : ${#vars}">
<td th:text="${var.key}"></td>
<td th:text="${var.value}"></td>
This is returning the same null error as well!
The only thing i could find on the web was a bug with Thymeleaf 2.1.4 that was caused by not having a HttpSession Object
https://github.com/thymeleaf/thymeleaf/issues/349
but then again, my URL1 works fine!
I haven't posted any code here because I'm not sure what else to post, please ask!
EDIT: Added Controller Code. /admin/questions is URL1 that works fine, '/admin/questionnaires' is URL2 that doesn't work.
#Controller
public class AdminController {
private QuestionRepository questionRepository;
private EQuestionnaireRepository eQuestionnaireRepository;
private EQuestionnaire eQuestionnaire;
#Autowired
public AdminController(QuestionRepository questionRepository,
EQuestionnaireRepository
eQuestionnaireRepository){
this.questionRepository = questionRepository;
this.eQuestionnaireRepository = eQuestionnaireRepository;
eQuestionnaire = eQuestionnaireRepository.findAll().get(0);
}
#RequestMapping(value = "/admin/questions", method=RequestMethod.GET)
public String questionForm(Model model) {
model.addAttribute("question", new Question());
return "questionForm";
}//-->This Works fine
#RequestMapping(value = "/admin/questions", method=RequestMethod.POST)
public String saveQuestion(#ModelAttribute Question newQuestion, BindingResult bindingResult, Model model) {
if( bindingResult.hasErrors())
{
System.out.println(bindingResult);
System.out.println("BINDING RESULTS ERROR");
return "questionForm";
}
questionRepository.save(newQuestion);
return "questionForm";
}
#RequestMapping(value = "/admin/Questionnaires", method=RequestMethod.GET)
public String QuestionnaireForm(Model model){
model.addAttribute("ListofQ",eQuestionnaire.getQuestionList());
return "questionnaireForm";
UPDATE: I changed over to thymeleaf 2.1.5-SNAPSHOT, and now I'm not getting the previously mentioned error - but a different error:
There was an unexpected error (type=Internal Server Error, status=500).
Exception evaluating SpringEL expression: "ask.questionText"
(questionnaireForm:13)
So now, the object reference is null in the template. It's not null when i put it into the Model (i've got System.out of the getQuestionText method inside the GET method, so thats confirmed)
This is the simple code I'm trying in the template:
<table>
<tr th:each= "ask : ${ListofQ}"></tr>
<tr th:text= "${ask.questionText}"></tr>
</table>
Here is the Question Object:
#Entity
#Table(name = "Questions")
public class Question {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long ID;
private int sequence;
private String questionText;
private int weightage;
private String option1 = "option1";
private String option2 = "option2";
private String option3 = "option3";
public Question() {
}
public Long getID() {
return ID;
}
public void setID(Long iD) {
ID = iD;
}
public int getSequence() {
return sequence;
}
public void setSequence(int sequence) {
if (sequence > 0) this.sequence = sequence;
}
public String getQuestionText() {
return questionText;
}
public void setQuestionText(String questionText) {
this.questionText = questionText;
}
public int getWeightage() {
return weightage;
}
public void setWeightage(int weightage) {
this.weightage = weightage;
}
public void setOption1(String option1) {
this.option1 = option1;
}
public void setOption2(String option2) {
this.option2 = option2;
}
public void setOption3(String option3) {
this.option3 = option3;
}
public String getOption1() {
return option1;
}
public String getOption2() {
return option2;
}
public String getOption3() {
return option3;
}
output in "each" need to be in the same statement , i think this will work for you
<table>
<tr th:each= "ask : ${ListofQ}" th:text= "${ask.questionText}"></tr>
</table>
You are not returning the model object to the Thymeleaf.
Try something like this:
#RequestMapping(value = "/admin/Questionnaires", method=RequestMethod.GET)
public ModelAndView QuestionnaireForm(Model model){
return return new ModelAndView("questionnaireForm", "ListofQ",eQuestionnaire.getQuestionList());
}

Resources