Handle JSP within a java class (Spring MVC) - java

I'm currently using Spring MVC 4 for developing a new web application.
I have four files named: header.jsp, menu.jsp, default.jsp and footer.jsp, they are basically the template of my webapp.
So, my default.jsp is the default template for every other page in my application, and it's basically like this:
...
<jsp:include page="header.jsp" />
<jsp:include page="menu.jsp">
<body>
Contents goes here
</body>
<jsp:include page="footer.jsp">
...
The Controller:
...
#RequestMapping("/")
public ModelAndView index() {
return new ModelAndView("default");
}
...
What i want to accomplish is make a java class that can handle header.jsp, one that can handle menu.jsp and so on... Since they will be dynamic pages and their content will change.
I know that i can use java code inside JSP, but that is what i don't wanna do.
Example of what i would like to do:
public class menu {
//this class handles menu.jsp
public List menuItems() {
ArrayList menuItems = new ArrayList();
menuItems.add("Home");
menuItems.add("Contact");
return menuItems;
}
}
And inside menu.jsp:
<%# codebehind="menu.java" %>
<ul>
<li> ${item[0]} </li> <!-- would output 'Home' -->
<li> ${item[1]} </li> <!-- would output 'Contact' -->
</ul>
Is that possible?

Yes that is possible, you just have to add model on your ModelAndView.
"menuItem" - will be name of your model.
"menu.menuItems()" - is your modelObject.
Controller
#RequestMapping("/")
public ModelAndView index() {
Menu menu = new Menu();
return new ModelAndView("default", "menuItems", menu.menuItems());
}
Menu
public class Menu {
//this class handles menu.jsp
public List menuItems() {
ArrayList menuItems = new ArrayList();
menuItems.add("Home");
menuItems.add("Contact");
return menuItems;
}
}
Rather than scriptlets, use jstl.
<%# codebehind="menu.java" %>
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<ul>
<c:forEach var="menu" value="${menuItem}">
<li><c:out value="${menu}"/></li>
</c:forEach>
</ul>
Also I would recommend you to use Apache Tiles with spring for better template framework.

Related

Sending dto with html file in Spring mvc

My current controller is returning to an HTML page. I want to send some data (a DTO) which can be received at front end, like an ajax response (like it happens in ajax + RestController). But this is not a RestController, it is a normal #controller returning HTML. I don't know even if it is possible to send DTO with html. There isn't much code to look at. I am just looking for feasibility. Do let me know if additional info is required. Thanks
Edit
Here is some code for reference. login.html is the page I am returning to. I want to send some additional info with this return ( in the form of a DTO ).
#Controller
public class LoginUserController {
#RequestMapping(value = {"/loginuser", "/loginuser?error"})
public String login() {
return "/login";
}
}
If you want to return view only i.e jsp in your case . You could put DTO object in modelMap and used inside jsp . Or simply if you want to return JSON only you could use #ResponseBody .
#RequestMapping(value = {"/loginuser", "/loginuser?error"})
public String login(ModelMap model) {
YourDTO dtoObject = // get DTO;
model.put("dtoObject",dtoObject)
return "/login";
}
class YourDTO {
private int id;
private String name;
// getters setters
}
Inside login JSP you can usedtoObject .
Name <c:out value="${dtoObject.name}" ></c:out> // Using JSTL
Or In Html file
<input type="text" id="name" value='${dtoObject.name}'/>
Seems like you're trying to build a spring boot web app, here is the bare minimum what you need to do:
Make sure your maven dependencies have spring-boot-starter-thymeleaf along with spring-boot-starter-webapp in the pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Configure/write your controller like this :
#Controller
public class LoginUserController {
#GetMapping(value = {"/loginuser", "/loginuser?error"})
public String login( Model model) {
model.addAttribute("message", "Aww snaps! something went wrong...");
return "login";
}
}
Ensure you have src/main/resources/templates/login.html which may look like this:
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Login Page</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p th:text="${message}" />
</body>
</html>
You can use any other viewing technology of your choice instead of Thymeleaf. Basically the viewing technology parses the HTML template, looks for expressions like
th:text
to reslove the value of
${message}
with the data that you've put in the model in Controller.
Hope this helps!
you can use following code
#Controller
public class LoginUserController {
#GetMapping(value = {"/loginuser", "/loginuser?error"})
public String login( Model model) {
organizationDTO = organizationService.getOrganizationDTO(id);
model.addAttribute("organizationDTO", organizationDTO);
return "/login";
}
}
and use below code in HTML page using JSTL
<div class="row">
<p class="col-md-4">${organizationDTO."your value"}</p>
</div>
eg below
<div class="row">
<label class="col-md-2">Id</label>
<p class="col-md-4">${organizationDTO.id}</p>
<label class="col-md-2">Name</label>
<p class="col-md-4">${organizationDTO.name}</p>
</div>

Should l make Spring Model class with one field?

I don't know should i make class with only one field which l will use as #ModelAttribute to get data from jsp? for example:
public class Age {
private int number;
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}}
And then using spring mvc form tag to fill this ModuleAttribute
<form:form action="processForm" modelAttribute="age">
<form:input path="number"/>
</form:form>
First of all, you need to create a controller :
#Controller
public class AgeController {
// this is to create an instance of Age and set in the model.
#RequestMapping("showForm")
public String showForm(Model model) {
model.addAttribute("age", new Age());
return "form"; // return form page.
}
// this is to print the age in the display page.
#RequestMapping("processForm")
public String processForm(#ModelAttribute("age") Age age) {
return "display"; // return display page where you will display the data populated in the form page.
}
}
Now, form page should look like :
<%#taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<!DOCTYPE html>
<html>
<!-- When you enter the data here, Spring will set the data in the Age bean by calling respective setter of the data members -->
<body>
<form:form action="processForm" modelAttribute="age">
Enter an age : <form:input path="number" />
<input type="submit" value="Submit" />
</form:form>
</body>
</html>
Now, display page should look like :
<%#taglib prefix="core" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<body>
The age is : ${age.number} <!-- Here getter is called internally -->
</body>
</html>
On clicking the submit, the display page will show the data.

Thymeleaf with SpringBoot - how to loop model and delete?

I am using SpringBoot with Thymeleaf to build a trivial example to help me learn the two technologies.
I am basing my example on THIS GUIDE
The entity is a Greeting which has an Id and a Content.
I create the Greeting just fine, and I can list all the Greetings I've created.
I then wanted to add a delete option against each Greeting in the list page. When clicking delete, I want the object to be deleted and the list page served up again.
Alas, when I load the list page I get this error:
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'greeting' available as request attribute
Controller and respository objects
#Controller
public class GreetingController {
#Autowired
GreetingRepo gr;
#RequestMapping(value="/greeting/list", method=RequestMethod.GET)
public String greetingsForm(Model model) {
model.addAttribute("greetings", gr.findAll());
return "greeting/list";
}
#RequestMapping(value="/greeting/delete", method=RequestMethod.POST)
public String deleteGreeting(#ModelAttribute("greeting") Greeting greeting) {
gr.delete(greeting);
return "redirect:/greeting/list";
}
}
#RepositoryRestResource
interface GreetingRepo extends JpaRepository<Greeting, Long> {
}
List.html page:
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Getting Started: Handling Form Submission</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<h1>Result</h1>
<div th:each="greeting : ${greetings}">
<p th:text="'id: ' + ${greeting.id}" />
<p th:text="'content: ' + ${greeting.content}" />
<form action="#" th:action="#{/greeting/delete}" th:object="${greeting}" method="post">
<input type="hidden" th:field="*{id}"/>
<input type="hidden" th:field="*{content}"/>
<input type="Submit" value="Delete"/>
</form>
</div>
Add another
Show All
</body>
</html>
Would appreciate a push in the right direction here :-)
I think you miss this line .
model.addAttribute("greeting", new Greeting());
#RequestMapping(value="/greeting/list", method=RequestMethod.GET)
public String greetingsForm(Model model) {
model.addAttribute("greeting", new Greeting());
model.addAttribute("greetings", gr.findAll());
return "greeting/list";
}
you dont have to use a form to delete the greeting you can do it very easily with this approach. hide the id of the greeting within the url. so you dont need to use a form and hidden tags. and annotate the controller method with following approach, to accept incoming id of the greeting.
replace the current form with given html code and replace the delete method in the controller as well.
<a th:href="#{/greeting/{id}/delete(id=${greeting.id})}" th:text="delete"></a>
#RequestMapping(value="/greeting/{id}/delete",method=RequestMethod.GET)
public String deleteGreeting(#PathVariable int id) {
gr.delete(id);
return "redirect:/greeting/list";
}
edit:- since you need the object to be present within the controller
you can use findOne method to fetch the object from the given id.check out the following example.
<a th:href="#{/greeting/{id}/edit(id=${greeting.id})}" th:text="edit"></a>
#RequestMapping(value="/greeting/{id}/edit",method=RequestMethod.GET)
public String Edit(#PathVariable int id){
greeting greetingob = gr.findOne(id);
return "edit";
}

In Spring MVC how do you store user input and reproduce it later on?

In one of my JSPs I get the user to enter some details about themselves. When they click submit I want the page that it redirects to, to remember the variable and then print it out.
e.g.
(register.jsp) Username: Barney
(welcome.jsp) Welcome Barney
(register.jsp) Username: Vernon
(welcome.jsp) Hello Vernon
Current code:
#RequestMapping(value = "/register", method = RequestMethod.POST)
public String register(ModelMap map, HttpSession session,
#RequestParam(value="givenUser") String givenUser) {
session.setAttribute("ans", givenUser);
map.addAttribute("displayAnswer", givenUser);
map.put("givenUser", givenUser);
return "register";
}
}
Request mapping for welcome:
#RequestMapping(value = "/welcome", method = RequestMethod.GET)
public String welcome() {
return "welcome";
}
and then in welcome.jsp I have: Hello ${givenAnswer}
register.jsp which once the link inside is clicked, goes to welcome.jsp
this is register.jsp
<%#taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%# page isELIgnored="false" %>
<html>
<head>
<title>SPRING ####### WEB</title>
</head>
<body>
<h2>SUCCESSFUL REDIRECTION!!!</h2>
<p>Register</p>
<form action="/HelloSpring/welcome" method="post">
Username: <input type="text" name="givenUser" >
Firstname: <input type="text" name="givenPassword">
Surname: <input type="text" name="givenSurname" >
Password: <input type="password" name="givenPassword">
<input type="submit" value="Submit">
</form>
</body>
</html>
welcome.jsp
<%#taglib uri="http://www.springframework.org/tags/form" prefix="spring"%>
<%# page isELIgnored="false" %>
<html>
<head>
<title>SPRING ####### WEB</title>
</head>
<body>
<h2>Spring Page Redirection</h2>
<p>Welcome ${givenUser}, your password is ${givenPassword}</p>
</body>
</html>
so my question is what have i not included because it currently just fires a blank when the user submits details
You can post the userinput attribute to the Controller and then send the value back in ModelMap.
Example:
#RequestMapping("/hello")
public String hello1(ModelMap map,#RequestParam String userInput){
/*your code goes here*/
map.put("userInput",userInput);
return "jsp1"; //first jsp name
}
and use it in jsp using expression language.
Hello {userInput}!!
The name in a <input> tag is what is used as request parameter name on form submission.
You should at least change your controller code to use correct parameter name :
#RequestMapping(value = "/answer", method = RequestMethod.GET)
public String answer(ModelMap map, HttpSession session,
#RequestParam("howareyou") String givenAnswer) {
session.setAttribute("ans", givenAnswer);
map.addAttribute("displayAnswer", givenAnswer);
map.put("givenAnswer", givenAnswer);
return "answer";
}
}
I also removed unused parameter req since Spring gives you directly the HttpSession. And it is normally no use to add the same object twice in the model. But I assume you were not sure of what was correct and tried both - any of them is correct and is enough :-)
SUCCESS! apparently it needed ${ param.elc }. why is this not on any tutorials and how come no one knew about it? im a bit skeptical still but it's doing as required.
thanks to all who helped!

Forward from JSP to another JSP without using a servlet between them?

I have a JSP page :
employee5_searchByName.jsp
<%#page import="java.util.Iterator"%>
<%#page import="java.util.List"%>
<!-- EMPLOYEE wants to search items by their name -->
<!DOCTYPE html>
<html>
<head>
<title>Employee - Search for items by name</title>
<link rel="stylesheet"
href="./css/styles.css"
type="text/css"/>
<link rel="stylesheet" type="text/css" href="css/jquery.autocomplete.css" />
<script src="http://www.google.com/jsapi"></script>
<script>
google.load("jquery", "1");
</script>
<script src="js/jquery.autocomplete.js"></script>
<style>
input
{
font-size: 120%;
}
</style>
</head>
<body>
<h1>Employee - Search for items by name</h1>
<h1>
Search for items by name
</h1>
<fieldset>
<legend>Please enter the item's name :</legend>
<form action="Employee5_After">
Item's name : <input type="text" name="prod_name" id="myProduct"><br>
<script>
$("#myProduct").autocomplete("autocompleteFromDb.jsp");
</script>
<input type="submit" value="Register">
</form>
</fieldset>
</body></html>
It forwards to this servlet :
Employee5_After
package controller.employee;
/**
* Retrieve the record of a given product by its name
* using hibernate
* #author X
*
*/
#WebServlet("/Employee5_After")
public class Employee5_After extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
// grab the product's name that the user entered
String productName = request.getParameter("prod_name");
// create DB instance
DatabaseInventory inventory = new DatabaseInventory();
// get the details
String details = inventory.getProductDetailsByName(productName);
HttpSession session = request.getSession();
// forward answer to JSP
synchronized(session)
{
if (details != null) // then the product has been found
{
session.setAttribute("foundProd", details);
String addressPath = "/WEB-INF/results/employee/employeeResult5.jsp";
RequestDispatcher dispatcher = request.getRequestDispatcher(addressPath);
dispatcher.forward(request, response);
}
}
}
}
That servlet is doing his stuff , and then forwards to a 2nd JSP ,called :
employeeResult5.jsp
<!-- Employee - get a description of a product by its name -->
<!DOCTYPE html>
<html>
<head><title>The details for the product you requested are below</title>
<link rel="stylesheet"
href="./css/styles.css"
type="text/css"/>
</head>
<body>
<h1>Here are the details from the product you request :</h1>
<h2>${foundProd}</h2>
<h1>We wish you well - bye bye!</h1>
<fieldset>
<legend>Go back to Employee's web-page</legend>
<form action="blablabla">
Press here to continue
</form>
</fieldset>
</body></html>
I guess that I can use the <% and %> in the JSP to do the logic side of the servlet (contacting to DB and retrieve data) . How can I avoid using a servlet in between , and just pass the data from one JSP to another JSP ?
You can use the request.redirect(URL) method to do it.
Or you can use request. forward(req, resp).
See example
Separate the business logic from the font end, there is no need to redirect to an intermediate servlet. The best practice is to put the business logic in a separate class and instantiate that class in the destination page. Here is one example:
mainPage.jsp - create the page similar to your employee5_searchByName.jsp. Now this page posts the data you enter.
Create a backing class called - dbData.java (DatabaseInventory in your case)- put all your database query here and functions to retrieve what your want. A function like public String searchText(String param) (similar to getProductDetailsByName(productName)) which will essentially fetch your search results from database.
Now the most important part - Instantiate this class in your destination SearchResults.jsp page and show whatever data you get in a manner similar to this:
<%#page import="mysource.dbData"%>
<%
searchParam = request.getParameter("searchStr");
dbData data = new dbData();
String result = data.searchText(searchParam);
%>
<HTML>
<BODY>
The result is: <% out.print(result); %>
</BODY>
</HTML>
The industry standard is to follow an MVC Architecture. Following that will create applications which are clear to understand and easy to maintain.
Try this code to forward with parameteres
<jsp:forward page="URL">
<jsp:param nama="param1" value="hello"/>
<jsp:param nama="param2" value="hello2"/>
<jsp:param nama="param3" value="hello3"/>
<jsp:param nama="param4" value="hello4"/>
.
........... and so on
</jsp:forward

Categories