ViewResolvers -> JSP, Restful service, html page
servlet-config -> Configuration file
POJO -> Plain old java object
Bean -> Spring configured POJO
After downloading from Spring Initializr:
1. Import the project in IntelliJ
2. Just follow the Problems Faced: in Spring Boot
3. Then RUN. It should give WhiteLabel Error
4. Add html file in src/resources/static. Just add hello in index.html
5. And restart. You should be able to see hello.
Demo: Greeting Controller
src/main/ -> Root Folder
<root>/java
<root>/webapp -> You can keep index.html and serve it from here
/webapp/WEB-INF/jsp -> To keep jsp file
greetings.jsp:
This will be similar to html but we can have variables here we have
${message}
/com.pluralsight.conference -> Keep our java class (ConferenceApplication.java)
We have annotation -> @SpringBootApplication. On top of default java code we do extend
public class ConferenceApplication extends SpringBootServletInitializer
Create a Java Class with name controller.GreetingController. In this controller is directory.
Controller -> Is use to control what to put in web page. Only handle request/response. Don't put business logic. @Controller
Service -> Business logic. Describe verbs/action of system. @Service
Repository -> Data access object. Describe nouns. Database interaction. @Repository
Controller:
Heart and soul of spring MVC. Lightweight. In our example we just used @Controller annotation and Request Mapping @GetMapping. There are other ways to do it by extending a class but the method shown here is preferred.
DEMO: Registration Controller + Greetings Controller
1. Create directory under main -> webapp/WEB-INF/JSP
2. Go to Setting CTRL + ALT + s. Under Build Execution & Deployment -> Application Server choose Tomcat (NOTE: We do this because if we right click we don't get JSP, so just following tutorial). Also download and install tomcat (unzip)
3. Change the packaging type to WAR. In pom.xml ad <packaging>war</packaging> This need to be added between version and name of com.pluralsight groupid XML tags.
4. Add tomcat dependency in pom.xml, this will be second dependancy, next to org.springframework.boot
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
5. Click on "Conference Application" which will allow to edit config. It is near hammar symbol in tool bar and press "Edit Configuration"
6. Click + sign and add tomcat server. Check JRE is 11. Click deployments tab -> + sign -> Artifacts -> Conference.war. Change application context to /conference instead of /conference_war
7. JSP Files and Index.html - Create greetings.jsp under webapp/WEB-INF/JSP and add this tag <h1>${message}</h1>. Also create registration.jsp webapp/WEB-INF/JSP and add this tag <h1>Registration</h1>. In resource/static/index.html put below lines:
<a href="registration">Registration</a>
<a href="greeting">Greeting</a>
Note: Intellij add '/' to href. But it is not required.
8. Modify ConferenceApplication.
public class ConferenceApplication extends SpringBootServletInitializer -> We do this basically to support tomcat
Add below parameters
src/main/resources -> application.properties
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
9. Under com.pluralsight.controller, create controller.GreetingController class
GreetingController.java
@Controller
public class GreetingController{
@GetMapping("greeting") --------> This is what we see in URL. When we hit greeting URL we will run below method
public String greeting (Map<String, Object> model){ ------> Here the name greeting is the method can be anything. foo or bar. Mapping string to object
model.put("message", "Hello Google"); ------> The above model variable is defined here. message is the variable in JSP page. Hello Google is the value
return "greeting"; ------> Here greeting is the JSP page not our method name. It will look for jsp page named greeting to substitute variable. We use only "greeting" because we have mentioned prefix as /WEB-INF/jsp/ and suffix and .jsp in application.properties. It know to look for application.properties because of @SpringBootApplication and public class ConferenceApplication extends SpringBootServletInitializer in our Main program.
}
}
10. Run the code. Go to this URL -> http://localhost:8080/conference/greeting
NOTE: While following tutorial I created index.hml under Resources/Static and when I hit /conference it pulled that page automatically. There is not configuration anywhere. It is hosted in /conference because when setting up tomcat we set our application context as /conference in step 6.
Whitelabel Error -> It occurs when either no html page is present or asp page is present but no code for it. Or code present no asp page for it.
11. Creating RegistrationController.java. It is same as greeting we just don't have model.put as we don't use any variable in the jsp for registration.
@Controller
public class RegistrationController {
@GetMapping("regsitration")
public String GetRegistration(Map<String, Object> model){
return "registration";
}
}
Model Attribute
This is for getting input from the user.
DEMO: Passing Parameters
1. In registration.jsp, create form tag:
In 2nd line:
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
Below h1 tag:
<form:form>
<table>
<tr>
<td>
Name:
</td>
<td>
<form:input path="name" />
</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="Add Registration">
</td>
</tr>
</table>
</form:form>
2. Save above and just restart. It will give error for path="name". It is because binding is missing. Right click on src/main/java/com.pluralsight.conference and create new class. model.Registration.
Registration.java
public class Registration {
private String name;
1. Right click -> Generate -> Getters and Setters
}
3. Go to RegistrationController.java
Change this line from public String GetRegistration(Map<String, Object> model) to public String GetRegistration(@ModelAttribute("registration")Registration registration) ---> Here we are naming our Model Attribute as registration, We can name anything, but the same name has to go inside the form in registration.jsp. Registration registration is the Registration Model object, and we are instantiating one registration.
4. Go to registration.jsp
<form:form> to <form:form modelAttribute="registration">
5. Restart the server. It will work and display HTML page properly but it won't be able to get input and store. Because in we need to do "post" mapping. If we look at registrationContoller.java we just have @GetMapping.
6. Open registrationContoller.java add below lines after return "registration"; }. Add below block
@PostMapping("regsitration")
public String addRegistration(@ModelAttribute("registration")Registration registration){
System.out.println("Registration: " + registration.getName()); //getName() is getter, it showed automatically in intelliJ
return "registration";
}
Creating Views in Spring MVC:
We created WEB-INF so that we serve our application via code. If we just add "registration.jsp" in the URL it won't serve, it just give error. We do this because use can't deeplink our application. In above code, we are making service call to registration to greeting.
Overriding extends SpringBootServletInitializer which we defined in Main class. Without using that we have to write below code to get same feature. But we don’t have to remove that extends SpringBootServletInitializer .
1. Right click on com.pluralsight.conference and add new class -> ConferenceConfig
ConferenceConfig.java
@Configuration
{
@Bean
public ViewResolver viewResolver(){
InternalResourceViewResolver bean = new InternalResourceViewResolver();
bean.setPrefix("/WEB-INF/jsp/");
bean.setSuffix(".jsp");
bean.setOrder(0);
return bean;
}
}
2. Comment the prefix and suffix settings in application.properties. Restart application
Creating Static Files in Spring MVC - PDF:
1. Right click on WEB-INF and create new directory pdf
2. Drag and drop a sample PDF file in the application
3. Go to Conference config.java
public class ConferenceConfig implements WebMvcConfigurer{
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/files/**").addResourceLocations("/WEB-INF/pdf/"); //files is the URL and ResourceLocation is the path in our project
}
//Do it above @Bean
}
}
4. Restart the server and go to URL conference/files/<pdfname>.pdf
Demo: Adding Internationalization:
1. Open ConferenceConfig.java
2. Add below bean
<PDF Code>
//We are going to override a feature from WEB MVC. We are registering localechange interceptor
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}
//It ties our current session to a locale. Below bean will create a instance and put in spring registry. Here we are using US locale
@Bean
public LocaleResolver localeResolver(){
SessionLocaleResolver slr = new SessionLocaleResolver();
slr.setDefaultLocale(Locale.US);
return slr;
}
//LocaleChangeInterceptor will look for a parameter either through hidden element or URL string as a query parameter. We are looking for program name lang
@Bean
public LocaleChangeInterceptor localeChangeInterceptor(){
LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
lci.setParamName("lang");
return lci;
}
<View Resolver Code>
3. Right click on "Resources" directory and create file -> "messages.properties". Notice the messages is plural and it matters
4. Inside messages.properties files write below
#lables
name=Name
#buttons
save.changes=Save Changes
5. Right click on "Resources" directory and create file -> "messages_es.properties".
name=Nombre
save.changes=Guardar cambios
6. Open registration.jsp (webapp/WEB-INF/jsp) and add below tag
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
7. Change the JSP code to accommodate the internationalization:
Replace "Name" with <spring:message code="name" />
8. Restart and see whether it worked.
Open regsitraiton link and add query parameter at end ?lang=es
9. For post-redirect-get: Once we submit the form, we need to again reload the page with no values. To do that GET request is sent locally. This is easy in this tutorial because @GET and @POST is separate.
In RegistrationController.java just makes changes to return under @PostMapping("registration"):
return "redirect:registration";
Demo: Thymleaf
Backup the old code before moving to this.
1. First add dependancy in pom.xml between spring-boot-starter-tomcat and spring-boot-starter-test, So this order matters because that’s how it get loaded in the class path.
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
2. Template Resolver is not same as view resolver, but feels same like it.
In ConferenceConfig.java
public class ConferenceConfig implements WebMvcConfigurer{
@Autowired
private ApplicationContext applicationcontext;
//After ViewResolver Bean
@Bean
public SpringResourceTemplateResolver templateResolver() {
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setApplicationContext(applicationContext);
templateResolver.setPrefix("/WEB-INF/views/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode(TemplateMode.HTML);
return templateResolver;
}
3. Template Engine: We don't need engine when we use jsp but required when thymleaf is used. This will call template resolver method.
//After SpringResourceTemplateResolver Bean
@Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver());
templateEngine.setEnableSpringELCompiler(true);
return templateEngine;
}
4. View Resolver: It is different from template resolver. Template resolver will lookup the actual template ViewResolver just takes whicever template was loaded. They work in conjunction.
//After viewresolver for jsp
@Bean
public ViewResolver thymeleafResolver() {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
viewResolver.setOrder(0);
return viewResolver;
}
Then edit viewResolver.setOrder(0); of JSP and set it to 1. So we are giving priority to Thymeleaf
5. Right click on webapp/WEB-INF -> Create directory "views" -> Create new HTML5 "thyme.html"
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Template</title>
</head>
<body>
<h1>Thymeleaf Integration</h1>
<p th:text="${message}"></p>
</body>
</html>
6. In above code we have "message" so this needs to populated using greetings controller:
In GreetingController.java, below the existing jsp code copy below, here we are creating new mapping for thyme.
@GetMapping("thyme")
public String thyme (Map<String, Object> model){
model.put("message", "Hello Thymeleaf");
return "thyme";
7. Save and restart the server and go to conference/thyme we will get the "Hello Thymeleaf". If we go to greeing or registration page it will break with 500 error.
JSR Bean Validation - Theory
JSR 303 -> Original Specification.
JSR 349 -> Targetted JAVA 7
JSR 380 -> Java 8 and focusses modularity changes in Java 9
Validator Interface: Theory
Bean validator reference implementation is instance of hibernate validator. In pom.xml between spring-boot-starter-tomcat and
Demo Validation: (We are using JSR 389)
1. Add below dependancy in pom.xml
spring-boot-starter-test add below dependancy:
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.1.1.Final</version>
</dependency>
Hibernate is for database however hibernate_validator can be used for data validation.
2. Open Model -> Registration:
public class Regsitration{
@NotEmpty //Validating input is not empty
3. Open RegistrationController.java
@PostMapping("regsitration")
public String addRegistration(@Valid @ModelAttribute("registration")Registration registration, BindingResult result){
if(result.hasErrors()){
System.out.println("There were errors");
return "registration";
}
4. Open registration.jsp
Inside head tag put following css
<style>
.error {
color: #ff0000;
}
.errorblock {
color: #000;
background-color: #ffEEEE;
border: 3px solid #ff0000;
padding: 8px;
margin: 16px;
}
</style>
Below <form:form moduleAttribute
<form:errors path="*" cssClass="errorblock" element="div" />
5. Restart server and try submitting without anything in box. It is validating for empty submits.
6. To get more errors
Under <form:input path="name"
<td>
<form:errors path="name" cssClass="error" />
</td>
Change <td colspan="2" to <td colspan="3"
7. In messages:
In messages.properties:
#validations
NotEmpty.registration.name=Name can not be empty. please fix
In messages_es.properties:
NotEmpty.registration.name=Name can not be empty, in Spanish
8. Restart, it should now show "Name can not be empty"
Demo: @RestController
1. Right click on Model and create new java class -> User. Below we are creating model object which we can pass back and forth to controller.
public class User {
private String firstname;
private String lastname;
private int age;
Right Click -> Generate -> Getter and Setter -> Select all three
}
2. Right click on Controller -> UserController. In RestController we are returning Body but in @Controller we were returning actual JSP page.
@RestController
public class UserController{
@GetMapping("/user")
public User getUser(@RequestParam(value = "firstname", defaultValue = "Bryan") String firstname,
@RequestParam(value = "lastname", defaultValue = "Hansen") String lastname,
@RequestParam(value = "age", defaultValue = "43") int age
) {
User user = new User();
user.setFirstname(firstname);
user.setLastname(lastname);
user.setAge(age);
return user;
}
}
Normally line with set will be a database call.
3. Now restart and add conference/user to the end. You will get json.
Demo: @PostMapping:
In usercontroller.java
1. Under the RestController logic
@PostMapping("/user")
public User postUser (User user) {
System.out.println("User firstname:" + user.getFirstname());
return user
}
Demo: Jquery
1. Right click on Resource -> Static -> New -> user.html and user.js
2. In user.js page below script
$(document).ready(function() {
$.ajax({
url: "http://localhost:8080/conference/user"
}).then(function(data) {
$('.firstname').append(data.firstname);
$('.lastname').append(data.lastname);
$('.age').append(data.age);
});
});
3. Copy HTML file from the exercise and paste to user.html
No comments:
Post a Comment