Why doesn't ModelAndView add a property? - spring

i have such a RestController
#Controller
public class ExchangeRateController {
private final static Logger LOGGER = LoggerFactory.getLogger(ExchangeRateController.class);
#GetMapping(value = "/current")
public ModelAndView geExchangeRate(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("Response.html");
modelAndView.addObject("resultUrl",url);
modelAndView.addObject("embedUrl",embedUrl);
return modelAndView;
}
}
Inside, I get the URL of the image and want to embed it using Model on my page.But it gives me an error 404 or an empty page, although if to take these addresses and just write in an html file, then everything works.How can this be done so that they are added to the place of scr and href?
<!DOCTYPE HTML>
<html>
<head>
</head>
<body>
<iframe src="${resultUrl}" width="980" height="560" frameBorder="0" class="giphy-embed" allowFullScreen></iframe>
<p>text</p>
</body>
</html>

Try to use #Controller instead of #RestController and change #RequestMapping("/current")

Use th:src and th:href.
<iframe th:src="${resultUrl}" width="980" height="560" frameBorder="0" class="giphy-embed" allowFullScreen></iframe>
<p><a th:href="${embedUrl}">text</a></p>

Related

#RequestMapping at class level

I'm new to springboot. I want to create a class with #RequestMapping at class level. I have a static html file located resource/static/main/index.html
#Controller
#RequestMapping("/home")
public class HomeController {
#GetMapping
#ResponseBody
public String Welcome(){
return "Hello World";
}
#GetMapping("/message")
public String message(){
return "main/index.html";
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport"
content="width=device-width, initial-scale=1, user-scalable=yes">
<title>Hello Message!</title>
</head>
<body>
Welcome everyone!
</body>
</html>
http://localhost:8080/home display Hello World in my browser. When I enter http://localhost:8080/home/message, I get a 404 message, The origin server did not find a current representation for the target resource or is not willing to disclose that one exists. If I remove #RequestMapping("/home") from the class level then it works. My goal is to have mulitple #GetMapping and #RequestMapping at the class level
If you are using thymeleaf then try:
#GetMapping("/message")
public String message(){
return "main/index";
}
The index view location must be resources/templates

HTML Page Doesn't Show Up on Springboot Application

I'm trying to create a registration page. The website is very simple, homepage will be returning signup page and when clicked "Submit" it should save it to the database. But I'm having trouble with getting the page.
Applicant.java
import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import java.util.Date;
#Entity
#Table(name = "bayilik_basvuru")
public class Applicant {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#NotBlank(message = "İsim Soyisim Girilmelidir.")
#Column(name = "isim_soyisim")
private String adSoyad;
public Applicant() {
}
public String getAdSoyad() {
return adSoyad;
}
public void setAdSoyad(String adSoyad) {
this.adSoyad = adSoyad;
}
}
Controller
#Controller
public class HomeContoller {
#Autowired
private ApplicantDAO dao;
#RequestMapping("/")
public ModelAndView getApplicationPage(){
ModelAndView model = new ModelAndView();
Applicant applicant = new Applicant();
model.addObject("applicant",applicant);
model.setViewName("index");
return model;
}
#PostMapping("/save")
public String saveApplicant(#Valid Applicant applicant, BindingResult result){
if (result.hasErrors()) {
return "add-student";
}
dao.save(applicant);
return "index";
}
}
Index.html -> form's piece,
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<title>Bayilik Ön Başvuru Formu</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> <link rel="stylesheet" type="text/css" th:href="#{../css/style.css}" />
<link rel="stylesheet" type="text/css" th:href="#{../css/bootstrap-datetimepicker.min.css}" />
<link rel="stylesheet" type="text/css" th:href="#{../css/roboto-font.css}" />
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</head>
<body>
<form class="form-horizantal" th:action="#{/save}" th:object="${applicant}"
method="POST">
<div class="form-group">
<label class="col-md-4 control-label">İsim Soyisim</label>
<div class="col-md-8">
<input type="text" th:field="*{adSoyad}" class="form-control" /> <!-- it gives error at this line at the start of the th:field-->
<span th:if="${#fields.hasErrors('adSoyad')}" th:errors="*{adSoyad}" class="text-danger"></span>
</div>
</div>
</body>
</html>
I have been dealing with this for hours. I've compared it to many examples and html file looks good, controller looks good I don't know what I'm doing wrong.
In my pom file I have thymeleaf;
<dependencies>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
...
<dependendcies>
By the way the error is this;
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Thu Oct 31 01:40:47 EET 2019
There was an unexpected error (type=Internal Server Error, status=500).
Error during execution of processor 'org.thymeleaf.spring5.processor.SpringInputGeneralFieldTagProcessor' (template: "index" - line 27, col 56) // this line is the same line I showed on the index.html file
You are not using the annotation #ModelAttribute on your /save endpoint . try using it like :
#PostMapping("/save")
public String saveApplicant( #Valid #ModelAttribute("applicant") Applicant applicant, BindingResult result){
if (result.hasErrors()) {
return "add-student";
}
dao.save(applicant);
return "index";
}
In your thymeleaf template th:object="${applicant}" expression declares the model object to use for collecting the form data. So , in your controller you have to use the annotation #ModelAttribute to bind the Applicant object to the incoming form content.
Change your get method to properly add the object:
#GetMapping("/") //simpler, more informative
public String getApplicationPage(Model model){
model.addAttribute("applicant", new Applicant()); //note method name
return "index";
}
Look at Project Lombok to greatly simplify your beans. You are missing a getter and setter for your id property and an annotation of #Getter and #Setter on the class would remove a lot of boilerplate.
You would also want the #ModelAttribute annotation on your post method for the Applicant parameter.
In the future, also please post your full stack trace.
It seems like there was an hierarchy problem on the project. Code worked after I fixed the hierarchy of files.
Thanks to repliers for their attempt to help but they couldn't know the core of the problem since I didn't attach the hierarchy's screenshot on the question.

How to let users download multiple files in Spring MVC using model object?

When users click a link, I need to show them Description, images as well as send multiple files for them to download.
I used Spring data to get an object with few String variables, List of images as well as documents from mongodb and added this object to Model. I am able to display Description and images after converting Binary data to String and using th:src="*{'data:image/png;base64,'+image}" on the html page. Till this part, it's fine. But I am not sure how to let users download pdf files which are in Binary format in the Model. Please help. Please see screenshots. When I open this page, along with Description & images, I should get a prompt that there are files for download. How can I acheive this
public class EventPostsDTO {
private String postId;
private Long eventId;
private String description;
private List<MultipartFile> images;
private List<MultipartFile> receipts;
private List<String> imgAsStrings;
private Map<String,Binary> receiptsMap;
private LocalDateTime creationDate;
private Event event;
//getters and setters
}
HTML Page with Thymeleaf
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
<title>Event Feed</title>
<link th:include="fragments/header::includecss">
</head>
<body>
<section th:replace="fragments/header::header"></section>
<br>
<br>
<br>
<section class="header4 cid-r8pwxTO9dF mbr-parallax-background"
id="header4-14">
<div class="container">
<h2 th:text="${event.eventName}"
class="mbr-section-title align-center pb-3 mbr-fonts-style display-1">
INTRO WITH IMAGE</h2>
<div th:each="post : ${posts}">
<div class="row justify-content-md-left">
<div class="media-content col-md-10">
<div class="mbr-text align-left pb-3">
<h3 class="mbr-text mbr-fonts-style display-5"
th:text="${post.description}"></h3>
<em class="mbr-fonts-style"
th:text="${'Posted on '+post.creationDate}">Intro with
background image, color overlay and a picture at the bottom.
Mobirise helps you cut down development time by providing you
with a flexible website editor with a drag and drop interface.</em>
</div>
</div>
<div th:each="image : ${post.imgAsStrings}">
<div class="mbr-figure pt-5">
<img th:src="*{'data:image/png;base64,'+image}" alt=""
width="100%" height="auto" class="imgdiv" />
</div>
</div>
<div th:each="receipt : ${post.receiptsMap}">
<embed src="pdfFiles/interfaces.pdf" th:src="${receipt.key}" width="600"
height="500" alt="pdf"
pluginspage="http://www.adobe.com/products/acrobat/readstep2.html">
</embed>
</div>
</div>
</div>
</div>
</section>
<section th:replace="fragments/footer::footer"></section>
<script
src="https://cdn.jsdelivr.net/npm/jquery-validation#1.17.0/dist/jquery.validate.min.js"></script>
</body>
Assuming you are using Spring Boot, Spring Data Mongo then you should consider using Spring Content Mongo for the content storage pieces like this:
Add the following dependencies to your pom.xml
<dependency>
<groupId>com.github.paulcwarren</groupId>
<artifactId>spring-content-mongo-boot-starter</artifactId>
<version>0.4.0</version>
</dependency>
<dependency>
<groupId>com.github.paulcwarren</groupId>
<artifactId>spring-content-rest-boot-starter</artifactId>
<version>0.4.0</version>
</dependency>
Make sure you have a GridFsTemplate bean present in your application context. Something like the following:
#Configuration
public class MongoConfig
#Bean
public GridFsTemplate gridFsTemplate() throws Exception {
return new GridFsTemplate(mongoDbFactory(), mappingMongoConverter());
}
...
To allow content to be associated with your Entity, give it the following attributes:
public class Event {
... other attributes ...
List<Image> images;
List<Recepit> receipts;
}
public class Image {
#ContentId
private String contentId;
#ContentLength
private long contentLength = 0L;
#MimeType
private String mimeType = "image/jpeg";
}
public class Receipt {
#ContentId
private String contentId;
#ContentLength
private long contentLength = 0L;
#MimeType
private String mimeType = "image/jpeg";
}
Add a store interface:
#StoreRestResource
public interface EventImage extends ContentStore<Image, String> {
}
#StoreRestResource
public interface EventReceipt extends ContentStore<Receipt, String> {
}
That's all that you need. When you application starts Spring Content will see the dependencies on the Mongo/REST modules and it will inject an implementation of the ImageStore and ReceiptStore for GridFs as well as an implementation of a controller that supports full CRUD functionality and maps those operations down onto the underlying store interfaces. You will have REST endpoints available under /events/{eventId}/images and /events/{eventId}/receipts.
So
curl -X PUT /events/{eventId}/images -F 'file=#path/to/local/image' will upload a new image and append it to the list List<Image>
curl -X GET /events/{eventId}/images/ will get you a list of images
curl -X GET /events/{eventId}/images/{contentId} will fetch an event image
curl -X DELETE /events/{eventId}/images/{contentId} will delete the event image
Receipts would work the same way.
There are a couple of getting started guides here. They use Spring Content for the filesystem but the modules are interchangeable. The Mongo reference guide is here. And there is a tutorial video here.
HTH

java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'newReward' available as request attribute

I'am new to Spring MVC, following the "Spring in Action" book, creating my own project from scratch. I get the following exception when trying to reach 'reward.jsp':
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'reward' available as request attribute
Contents of my classes:
reward.jsp
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%# taglib uri="http://www.springframework.org/tags/form" prefix="sf"%>
<html>
<head>
<title>Rewards</title>
</head>
<body>
<h1>Rewards module</h1>
<h2>Add reward</h2>
<sf:form action="add" method="post" modelAttribute="reward">
Reward name:<sf:input path="name" />
Point value:<sf:input path="pointValue" />
<input type="submit" value="Add">
</sf:form>
<br />
<h2>Reward list</h2>
<table>
<c:forEach var="reward" items="${rewardList}">
<tr>
<td>${reward.name}</td>
<td>${reward.pointValue}</td>
<td>delete</td>
</tr>
</c:forEach>
</table>
It works just fine when I delete form inputs.
RewardController.java
#Controller
public class RewardController {
#Autowired
private RewardService rewardService;
#RequestMapping("/reward")
public String listRewards(Map<String, Object> model) {
model.put("rewardList", rewardService.listReward());
return "reward";
}
#RequestMapping(value = "/add", method = RequestMethod.POST)
public String addReward(#ModelAttribute("reward") Reward reward,
BindingResult result) {
rewardService.addReward(reward);
return "redirect:/reward";
}
#RequestMapping("/delete/{rewardId}")
public String deleteContact(#PathVariable("rewardId") long rewardId) {
rewardService.removeReward(rewardId);
return "redirect:/reward";
}
}
Change your listRewards method, so that it add the form backing object to the model map model.put("reward", new Reward()).
#RequestMapping("/reward")
public String listRewards(Map<String, Object> model) {
model.put("rewardList", rewardService.listReward());
model.put("reward", new Reward())
return "reward";
}

In Struts2 I can't use modeldriven with validate

In the struts.xml:
<action name="User_UserFormSubmit" class="actions.UserManager">
<result name="input" >/jsp/user_form.jsp</result>
<result name="success" type="redirectAction"> success_register</result>
</action>
My class:
public class UserManager extends ActionSupport implements ModelDriven<User>{
private User user = new User();
#Override
public User getModel() {
return user;
}
public String validate() {
addActionError("blabla");
}
public String execute() {
return SUCCESS;
} ...
then in the jsp:
<s:property value="getActionErrors()"/>
I expect in the input result :
<li> blabla </li>
I succefully arrived to user_form.jsp, but the actionError does not appear
I tried without the "implements ModelDriven" and it work
The model driven erase the actionErrors (I supposed)
I want to use validate and modeldriven ¿any idea?
Not a big fan of model driven... but here is an example.
Before the example please note that using validate() does not make much sense in terms of ModelDriven. The reason is that the Model should be used over several actions and so the validation should probably be consistent. You don't use model driven just to make property names a bit shorter (to do that you use the struts2 push tag). As such validation should be done with xml as the model is bigger than any one action. Each action which uses that model uses the Visitor validator. This validator merely looks up the xml validation file for the model. The following example however will use the validate() method in the action to save time.
The following example will use the struts2-conventions-plugin to reduce the example size (adding it to your project is simply a matter of adding one jar).
create: com.quaternion.action.AddUser
package com.quaternion.action;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
public class AddUser extends ActionSupport implements ModelDriven<User>{
User user = new User();
#Override
public User getModel() {
return user;
}
#Override
public void validate(){
if (user.age != 12) {
super.addActionError("bla bla bla");
}
}
}
create: com.quaternion.action.User
package com.quaternion.action;
public class User {
public String name;
public int age;
}
create: /WEB-INF/content/add-user-input.jsp
<%#taglib prefix="s" uri="/struts-tags"%>
<%#page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title>Form</title>
</head>
<body>
<h1>Form</h1>
<s:actionerror/>
<s:form action="add-user">
<s:textfield name="name"/>
<s:textfield name="age"/>
<s:submit/>
</s:form>
</body>
</html>
create: /WEB-INF/content/add-user-success.jsp
<%#taglib prefix="s" uri="/struts-tags"%>
<%#page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title>Success</title>
</head>
<body>
<h1>Success</h1>
</body>
</html>
To test:
Add /add-user-input as the action name on your context path. If you enter an age of 12 you will get the success page, if you enter anything else you will get an action error. This has been tested to work. It is possible a typo was made, but the main thing to take away is there is an error in your application, using both conventions or xml there should be no issues with what you are doing.
You can also validate with #validations too, you have access to model driven object in the validator.
#Action(value = "save-user")
#Validations(
stringLengthFields = {
#StringLengthFieldValidator(fieldName = "name", trim = true, key = "validate.required.string.length"),
#StringLengthFieldValidator(fieldName = "age", trim = true, key = "validate.required.string.length"),
#StringLengthFieldValidator(fieldName = "address.addLine1", trim = true, key = "validate.required.string.length")
})
public String save() {

Resources