kychua / spring-demo

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Readme

This project aims to develop a Java web application starting from the most basic, then layering in additional tools and frameworks progressively to help users understand the roles of such tools and frameworks. This project builds on the code in "How to Install Apache Tomcat 9 (on Windows, Mac OS X, Ubuntu) and Get Started with Java Servlet Programming" tutorial by Chua Hock-Chuan, and incorporates code from other tutorials.

Setup

  1. Set up Java project using Maven

    1. Generate project using Maven with archetype maven-archetype-webapp.

    2. Add java folder to src/main.

      • Java code are stored in src/main/java

      • HTML files are stored in src/main/webapp

      • web.xml stores mappings from url patterns to Java servlets.

      • Configuration settings are stored in pom.xml.

  2. Set up Maven wrapper with command

    mvn -N io.takari:maven:wrapper
  3. Set up database

    1. Install MySQL using installer (take note of root password)

    2. Start MySQL server in C:\mysql\bin: mysqld --console. Run client (mysql -u <username> -p) in other shells.

    3. Use root account to create new user account and grant permissions:

      mysql -u root -p
      create user 'myuser'@'localhost' identified by 'xxxx';
      grant all on _._ to 'myuser'@'localhost';
      quit;
    4. Use new user account to create database:

      create database if not exists ebookshop;
      
      use ebookshop;
      
      drop table if exists books;
      create table books (
          id int NOT NULL AUTO_INCREMENT,
          title varchar(50),
          author varchar(50),
          price float,
          qty int,
          primary key (id));
      
      insert into books values (1001, 'Java for dummies', 'Tan Ah Teck', 11.11, 11);
      insert into books values (1002, 'More Java for dummies', 'Tan Ah Teck', 22.22, 22);
      insert into books values (1003, 'More Java for more dummies', 'Mohammad Ali', 33.33, 33);
      insert into books values (1004, 'A Cup of Java', 'Kumar', 44.44, 44);
      insert into books values (1005, 'A Teaspoon of Java', 'Kevin Jones', 55.55, 55);
      
      select * from books;
    5. Create a test database.

      create database if not exists ebookshop_test;
    6. Add SQL to `pom.xml’s dependencies.

      <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.13</version>
      </dependency>
  4. Set up server (optional, for traditional .war deployment)

    1. Install Tomcat

    2. Create user account for deploying code to server: add user to tomcat/conf/tomcat-users.xml

      <role rolename="manager-gui"/>
      <role rolename="manager-script"/>
      <user username="admin" password="password" roles="manager-gui,manager-script" />
    3. Add server to maven/conf/settings.xml

      <server>
        <id>TomcatServer</id>
        <username>admin</username>
        <password>password</password>
      server>
    4. Add server to pom.xml plugins.

      <plugin>
      <groupId>org.apache.tomcat.maven</groupId>
      <artifactId>tomcat7-maven-plugin</artifactId>
      <version>2.2</version>
      <configuration>
          <url>http://localhost:8080/manager/text</url>
          <server>TomcatServer</server>
          <path>/${project.build.finalName}</path>
      </configuration>
      </plugin>
  5. Add Docker as per tutorial

    1. Set <packaging> to jar in pom.xml.

      <packaging>jar</packaging>
    2. Add Docker dependencies to pom.xml.

    3. Add Dockerfile.

    4. Add docker-compose.yml.

    5. Add application-docker.properties to configure database used in Docker.

    6. Add .dockerignore to prevent docker build from hanging. (See this for more info)

  6. Add Java, HTML and XML code as per tutorial (note that directory structure, SQL setup and Tomcat setup should be as per instructions above, not according to the tutorial). Files added:

    • src\main\java: HelloServlet.java, QueryServlet.java

    • src\main\webapp: index.html, querybook.html

    • src\main\webapp\WEB-INF: web.xml

  7. Add Spring/Spring Boot as per Spring’s tutorial.

    1. Add relevant entries to pom.xml. > If you get an error message No plugin found for prefix 'spring-boot' in the current project and in the plugin groups, try adding these entries.

    2. Add relevant code. > The SpringBootApplication must not be in the default package. Instead, move the application class into a package, i.e. src/main/java/hello/Application.java is ok but not src/main/java/Application.java

    3. Change the necessary files to support deploying to Tomcat via a .war file. > Ignore the instructions for creating application.properties as it is outdated.

    4. Create application.properties in src/main/resources with server.servlet.contextPath=/myapp so that the URL when deploying via spring-boot will be localhost:8080/myapp/…​ (same as deploying via Tomcat) instead of localhost:8080/…​.

    5. Change existing code to use Spring/Spring Boot.

  8. Add Swagger to document APIs

  9. Add Spring Data JPA Auditing. Spring Data Jpa’s auditing feature allows you to automatically record when an entity was created or last modified, and by whom.

    1. Create an abstract auditing entity class. Other entity classes will extend this class to enable auditing.

      1. Add @MappedSuperclass to the AbstractAuditingEntity, to denote inheritance structure for the database tables, where we are sharing properties/methods/associations among unrelated entities. See: other ways of implementing inheritance in JPA.

      2. Add an entity listener, AuditingEntityListener provided by Spring that handles the recording of changes.

      3. Add audit fields @CreatedBy, @LastModifiedBy, @CreatedDate, @LastModifiedDate (with getters and setters) to record changes.

    2. Make all entity classes extend AbstractAuditingEntity.

    3. Add AuditorAwareImpl to inform Spring of the current user making changes. This can be replaced with the current user when Spring Security is used.

    4. Add AuditConfiguration to tell Spring Data to use our own AuditorAware implementation.

Using Spring/Spring Boot

Why use Spring

The Spring Framework is a framework that helps you combine different components (e.g. databases, views) easily. This is done via dependency injection. Instead of having to fetch dependencies the code needs as it starts up, Spring lets you use such objects (beans) as if they already exist.

Spring instantiates, configures and manages the dependencies and supplies them to the code based on the configurations you supply. For example, you may configure Spring to use only one instance of PetShop, returning a cached instance for subsequent requests. Or, you may want Spring to return PetFood with amount of 1kg whenever you request SomeFood.

This is especially useful when you have many components that you want to combine in different ways or when you need to be able to swap components easily (e.g. in different settings/environments).

(Adapted from this answer)

Spring vs Spring Boot

Spring Boot is built on top of Spring, and simplifies the process of creating Spring projects by choosing convention over configuration. It provides sensible defaults, autoconfigurations and other useful features (e.g. monitoring).

Spring concepts

Spring IoC container (application context)/Dependency Injection

Spring implements the Inversion of Control (IoC) principle (or dependency injection) through the IoC container (application context). Objects define (but not fetch) their dependencies. The container then instantiates, configures and assembles those dependencies (beans) using configuration metadata (that you provide in XML, Java annotations or Java code) and injects those dependencies into the code. See a detailed example of DI in Spring Boot and more DI examples in Spring.

ApplicationContext, BeanFactory are interfaces that represent IoC containers. Spring generally recommends using ApplicationContext since it has more functionalities than BeanFactory.

Beans

Beans are objects managed by the Spring IoC container. They are created using the configuration metadata (e.g. XML bean definitions). For example, beans may be declared implicitly using stereotype annotations (one bean automatically created and configured per class), or declared explicitly using @Bean, usually in @Configuration classes.[1] See this article for examples of both ways of declaring beans.

@Bean annotates a method that returns an object to be registered as a bean, with the method’s body containing the logic for creating it. It allows you to configure the bean yourself e.g. when you want to use components from external libraries, where you don’t have the code to annotate with @Component.[2]

@Configuration denotes a class that provides configuration for beans.

Dispatcher Servlet (Spring MVC)

The dispatcher servlet serves as a front controller, processing all incoming requests and delegating tasks to special beans (like HandlerMapping, ViewResolver beans)[3].

When the dispatcher servlet receives a request, it

  1. Uses HandlerMapping to look for the appropriate handler (e.g. method in a @Controller class, wrapped in HandlerMethod instance) and interceptors (for pre- and post-processing).

  2. Invokes the handler via HandlerAdapter’s `handle(HttpServletRequest, HttServletResponse, handler) method. A ModelAndView object is returned.

    1. handle() invokes the handler, passing it the request and response as parameters.

      If interceptor handlers are used, pre-processing and post-processing are done before/after the handler processes the request.

    2. the handler executes the relevant logic and returns a ModelAndView object.

      Controller methods do not usually take in HttpServletRequest and HttpServletResponse as arguments, and do not necessarily return a ModelAndView instance. They can take in arguments like @RequestParam or Model, and return String (representing a view name), Model, @ResponseBody and more. It is the RequestMappingHandlerAdapter that resolves the arguments from the HttpServletRequest and creates a ModelAndView object from the return value.

  3. Processes the ModelAndView object, resolving the view if necessary and passing it the model data. View can be a String view name to be resolved using a ViewResolver, or a View object. The model is a Map (keys and associated values).

  4. Returns output in response.

For a more detailed explanation, see these articles.

Read this to see how @RequestMapping works.

References: [4] [5] [6]

Stereotype annotations

Classes annotated with @Component are automatically detected by Spring during component scanning. Spring auto-configures and creates beans from these classes, with the bean name the same as the class name, except with the first letter in lowercase.[7]

@Repository, @Service and @Controller are meta-annotations of @Component, and are thus also detected during component scanning. These can be used to denote the roles of components within the application.

  • @Repository: executes database related operations; catches platform-specific exceptions and rethrows as Spring’s unchecked data access exception

  • @Service: contains business logic and calls methods in repository layer

  • @Controller: controller; only classes annotated with @Controller can use @RequestMapping

[8]

@Autowired

Asks Spring for an instance of the annotated class that has corresponding bean. See this for an example.

SQL/JDBC/JPA/ORM/Hibernate/Spring Data JPA

Java data are stored in objects, whereas SQL (or other relational databases) data are stored in tables. The mismatch between the way objects and tables are designed is known as "object relational impedance mismatch". For example, * Attribute names and types may not match column names and types * Objects are shared whereas tables have relationships (e.g. one-to-many) * Multiple classes (e.g. subclasses) may be mapped to a single table and vice versa.

Before JPA, impedance mismatch was handled by translating results from queries to Java objects e.g. JDBC (Java database connectivity). This involves . Reading values from objects and setting them as query parameters . Converting query results to objects

This approach is difficult to use as queries can be very complex in large applications, and changes to the structure of the database would necessitate significant code rewrites.

An alternative approach is Object Relational Mapping (ORM), where we map objects to tables so that interactions with the database are done via objects (e.g. Book.query(author="Kumar")) instead of queries (SELECT * FROM books WHERE author = "Kumar"). (See this answer for more details.)

JPA (Java Persistence API) is a specification (interface) for implementing the ORM approach. The key components in JPA are: . Entity Manager: Handles interactions with the database. . Java Persistence Query Language (JPQL): Provides ways to write queries to search entities. Unlike SQL queries, JPQL already knows the mappings between entities. . Criteria API: Defines a Java-based API to search databases.

Note that JPA is only a specification - it provides guidelines for ORM libraries to follow but does not provide any functionality. For example, it provides annotations like @Entity and @Table, designed to be used to map objects to tables. However, without an implementation, these annotations will not do anything. In this project, we will use Hibernate. Hibernate’s JPA implementation, which follows the JPA’s specification, is what provides the actual functionality.[9] Spring Data JPA provides features that simplify the use of Hibernate, such as automatically generating queries through method name conventions and allowing users to define DAO interfaces (select, update, delete etc.) by extending repositories instead of having to write them. [10] [11]

(Adapted from this article)

HTML/JSP/Thymeleaf

Deploy

  • Using Spring

    mvn spring-boot:run
  • Using maven’s tomcat plugin:

    mvn tomcat7:deploy
    mvn tomcat7:undeploy
    mvn tomcat7:redeploy
  • Using maven + tomcat

    1. Generate .war file (generated to target by default)

      mvn package
    2. Copy .war file to C:\tomcat\webapps

    3. Start/stop tomcat with tomcat9.exe start, tomcat9.exe stop

About


Languages

Language:Java 93.2%Language:HTML 6.0%Language:Dockerfile 0.8%