SlideShare a Scribd company logo
IndieLabs
Forms App Using
Spring Framework
Spring Framework MVC Development
Abdulah Al Bahhar
7/21/2015
Table of Contents
1. Introduction ........................................................................................................................... 1
1.1. Application Overview .................................................................................................... 1
1.2. Outcomes........................................................................................................................ 1
1.3. Pre-requisites.................................................................................................................. 1
1.4. Requirements.................................................................................................................. 1
1.5. GitHub Repository ......................................................................................................... 1
2. STS Setup.............................................................................................................................. 2
2.1. STS Loading Main Class Bug........................................................................................ 2
2.2. POM.xml Dependencies................................................................................................. 3
2.2.1. JPA Dependencies................................................................................................... 3
2.2.2 Spring Security Dependencies.................................................................................. 3
2.2.3 Hashing Utilities Dependencies................................................................................ 4
2.2.4 AOP Dependency..................................................................................................... 4
2.2.5 Testing Dependencies............................................................................................... 4
2.2.6 MySQL Dependency................................................................................................ 4
2.3. Servlet-Context.xml Configuration................................................................................ 5
2.4. Datasource.xml Configuration ....................................................................................... 7
2.5. Spring-Security.xml Configuration ................................................................................ 8
2.6. Web.xml Configuration................................................................................................ 11
2.7. Packages....................................................................................................................... 13
2.8. Static Resources ........................................................................................................... 13
2.9. Class Diagram .............................................................................................................. 13
2.10. Database Schema........................................................................................................ 14
3. Models................................................................................................................................. 20
3.1. User .............................................................................................................................. 20
3.2. Role .............................................................................................................................. 24
3.3. Form ............................................................................................................................. 25
3.4. Question........................................................................................................................ 26
3.5. SimpleQuestion ............................................................................................................ 27
3.6. MCQuestion ................................................................................................................. 28
3.7. Choice........................................................................................................................... 29
3.8. SimpleAnswer .............................................................................................................. 30
3.9. ChoiceAnswer .............................................................................................................. 31
4. Repositories......................................................................................................................... 33
4.1. UserRepository............................................................................................................. 33
4.2. RoleRepository............................................................................................................. 33
4.3. FormRepository............................................................................................................ 33
4.4. QuestionRepository...................................................................................................... 34
4.5. SimpleQuestionRepository........................................................................................... 34
4.6. MCQuestionRepository................................................................................................ 34
4.7. ChoiceRepository......................................................................................................... 34
4.8. SimpleAnswerRepository............................................................................................. 35
4.9. ChoiceAnswerRepository............................................................................................. 35
5. Services ............................................................................................................................... 35
5.1. CustomUserDetailsService........................................................................................... 35
5.2. UserService .................................................................................................................. 38
5.3. RoleService .................................................................................................................. 39
5.4. FormService ................................................................................................................. 40
5.5. SimpleQuestionService ................................................................................................ 40
5.6. MCQuestionService ..................................................................................................... 41
5.7. ChoiceService............................................................................................................... 42
5.8. SimpleAnswerService .................................................................................................. 42
5.9. ChoiceAnswerService .................................................................................................. 43
6. MCQuestion Wrapper Class................................................................................................ 44
7. Controllers........................................................................................................................... 45
7.1. Home Controller........................................................................................................... 45
7.2. SecurityNavigation Controller...................................................................................... 46
7.3. FormsController ........................................................................................................... 47
7.4. SimpleQuestionsController .......................................................................................... 49
7.5. MCQuestionsController ............................................................................................... 51
7.6. SimpleAnswerController.............................................................................................. 54
7.7. ChoiceAnswerController.............................................................................................. 55
8. Views................................................................................................................................... 57
8.1. login-form.jsp............................................................................................................... 57
8.2. Users............................................................................................................................. 58
8.2.1. Register.jsp............................................................................................................ 58
8.3. Forms............................................................................................................................ 59
8.3.1. index.jsp ................................................................................................................ 59
8.3.2. details.jsp............................................................................................................... 61
8.3.3. create.jsp................................................................................................................ 63
8.3.4. edit.jsp ................................................................................................................... 64
8.4. SimpleQuestions........................................................................................................... 65
8.4.1. details.jsp............................................................................................................... 65
8.4.2. create.jsp................................................................................................................ 67
8.4.3. edit.jsp ................................................................................................................... 67
8.5. MCQuestions................................................................................................................ 68
8.5.1. details.jsp............................................................................................................... 68
8.5.2. create.jsp................................................................................................................ 70
8.5.3. edit.jsp ................................................................................................................... 71
9. Sample Screenshots............................................................................................................. 72
10. Useful Resources............................................................................................................... 74
1 | P a g e
1. Introduction
1.1. Application Overview
This tutorial will take you through learning how to develop a kind of simple Java EE
web application using Spring MVC. The idea of the application is very simple, we
have a collection of forms that contain two types of questions, written and multiple
choice. The admin can manage all of these, and the regular users can answer those
questions many times.
1.2. Outcomes
At the end of this tutorial, you should be able to achieve the following:
 Setup the development environment.
 Setup the XML configurations for dependencies, data source and Spring
Security.
 Create models with the proper relationships mapped to the database.
 Create services.
 Create repositories.
 Create controllers.
 Create views.
1.3. Pre-requisites
1. Good knowledge of development using Java SE.
2. Basic knowledge of MVC pattern.
3. Basic knowledge of HTML.
1.4. Requirements
To follow along with the tutorial, you should have the following:
1. STS IDE installed. (In this tutorial, version 3.6.4 is used)
2. JDK 1.6 or 1.7. (version 1.8 results in problems in the version of STS used,
not sure about higher versions of STS)
3. MySQL 5 database. (In this tutorial, Wamp server is used for this purpose)
1.5. GitHub Repository
All the final files of the project exist on the GitHub repository on the following link:
https://github.com/abahhar/FormsApp
2 | P a g e
2. STS Setup
First, we have to create a new Spring MVC project, you could create a new one and it
will create all the default files and directory structure we need.
To create a new Spring MVC Project, please do the following:
1. FileNewSpring Project.
2. Set the project name to FormsApp.
3. Choose Spring MVC Project.
4. Write the package name as: com.abahhar.formsApp.
5. Click finish.
The default Spring MVC project which is created contains a default HomeController
in the package “com.abahhar.formsapp” and a home.jsp webpage in the views folder.
This simple application shows you a hello world page with the current date and time.
To run the application, you could simply drag the application folder “FormsApp” to
the Pivotal tc server which exists in the window below the package explorer, and then
in the same window of the servers, you simply click the green arrow to run the
application.
2.1. STS Loading Main Class Bug
In the current version and the following one, there’s a bug in the IDE that results in
not running the application, you might encounter a statement in the output window
that says “Could not find or load main class”.
To solve the issue, please follow the first solution suggested in the following URL:
http://stackoverflow.com/questions/29004274/error-after-update-to-sts-3-6-4-release
3 | P a g e
2.2. POM.xml Dependencies
To be able to use libraries in Spring Framework, we should handle the dependencies
ourselves in pom.xml file which exists in the root document of our application. This
section provides you with the needed dependencies to be added.
2.2.1. JPA Dependencies
4. <!-- JPA Dependencies -->
5. <dependency>
6. <groupId>org.springframework</groupId>
7. <artifactId>spring-core</artifactId>
8. <version>${org.springframework-version}</version>
9. </dependency>
10. <dependency>
11. <groupId>org.springframework.data</groupId>
12. <artifactId>spring-data-jpa</artifactId>
13. <version>1.2.0.RELEASE</version>
14. </dependency>
15. <dependency>
16. <groupId>org.springframework</groupId>
17. <artifactId>spring-orm</artifactId>
18. <version>${org.springframework-
version}</version>
19. </dependency>
20. <dependency>
21. <groupId>org.hibernate</groupId>
22. <artifactId>hibernate-
entitymanager</artifactId>
23. <version>4.1.7.Final</version>
24. </dependency>
2.2.2 Spring Security Dependencies
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>3.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>3.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>3.1.3.RELEASE</version>
</dependency>
<!-- Spring Security tag library to be used in the views
-->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>3.1.3.RELEASE</version>
</dependency>
4 | P a g e
2.2.3 Hashing Utilities Dependencies
<!-- Hashing utilities dependencies -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.6</version>
</dependency>
2.2.4 AOP Dependency
<!-- AOP dependency -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2</version>
</dependency>
2.2.5 Testing Dependencies
<!-- Testing Dependencies -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${org.springframework-version}</version>
<scope>test</scope>
</dependency>
2.2.6 MySQL Dependency
<!-- MYSQL -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
5 | P a g e
2.3. Servlet-Context.xml Configuration
This configuration file exist in the following directory:
FormsAppsrcmainwebappWEB-INFspringappServlet
Please make sure that it contains the following code:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd"
xmlns:security="http://www.springframework.org/schema/security">
<!-- Enables the Spring MVC @Controller programming model -->
<mvc:annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently
serving up static resources in the ${webappRoot}/resources directory
-->
<mvc:resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by @Controllers to .jsp
resources in the /WEB-INF/views directory -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResol
ver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
<context:annotation-config/>
<context:component-scan base-package="com.abahhar.formsapp" />
<jpa:repositories base-package="com.abahhar.formsapp.repository"/>
<tx:annotation-driven/>
</beans>
6 | P a g e
Please notice this fragment of code:
<context:annotation-config/>
<context:component-scan base-package="com.abahhar.formsapp" />
<jpa:repositories base-package="com.abahhar.formsapp.repository"/>
<tx:annotation-driven/>
What this fragment does is that it scans for the Spring components and repositories in
the specified packages. Components can be controllers or services.
This scan is done automatically by Spring Framework in order to inject the
components and repositories later in the code, this is the dependency injection feature
supported in Spring Framework, later in the code when we want to inject a service or
repository, we will need to annotate it with @Autowired, and Spring Framework will
do the job of injecting the right dependency since it scans in the proper packages we
specified in this configuration.
Furthermore, notice the prefix and the suffix values specified by the default Spring
MVC Project, these values will be used to enable the ViewResolver to find the view
that we want. For example, in the controller we could return a string of a view as
“/forms/create”, this string will be evaluated as “WEB-INF/views/forms/create.jsp”.
As you notice, the prefix is added to the beginning of the returned string and the
suffix is added to the end of it.
7 | P a g e
2.4. Datasource.xml Configuration
Here we setup the configuration for the database connection, please be sure to include
the configuration file datasource.xml in the package “src/main/resources”, and include
the following fragment of code:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"
value="com.mysql.jdbc.Driver"/>
<property name="url"
value="jdbc:mysql://localhost/helloWorld"/>
<property name="username" value="root"/>
<property name="password" value=""/>
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactory
Bean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan"
value="com.abahhar.formsapp.domain" />
<property name="persistenceProviderClass"
value="org.hibernate.ejb.HibernatePersistence" />
<property name="loadTimeWeaver">
<bean
class="org.springframework.instrument.classloading.InstrumentationLoa
dTimeWeaver" />
</property>
<property name="jpaProperties">
<props>
<prop
key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.max_fetch_depth">3</prop>
<prop key="hibernate.jdbc.fetch_size">50</prop>
<prop key="hibernate.jdbc.batch_size">10</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"
/>
</bean>
</beans>
For your settings, put the correct link for the local server hosting the database and its
port if not 80, and the name of the database after the slash “/”, and the correct
username and password. In this tutorial, the name of the database is helloWorld.
8 | P a g e
2.5. Spring-Security.xml Configuration
Here we setup the configuration for Spring Security. Spring Security is a ready library
that is used for authentication and authorization of users. Using the following library,
we can have a login system and every user could have roles which with he can be
authorized to the different parts of the application.
Please be sure to include the configuration file spring-security.xml in the package
“src/main/resources”, and include the following fragment of code:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-
3.1.xsd"
xmlns:security="http://www.springframework.org/schema/security">
<context:annotation-config />
<context:component-scan base-package="com.abahhar.formsapp.service"
/>
<jpa:repositories base-package="com.abahhar.formsapp.repository"/>
<!-- Spring Security Configuration -->
<security:http pattern="/resources/**" security="none"/> <!--
Permit access to static resources -->
<security:http auto-config='true' use-expressions="true"> <!-- use-
expressions enables using expressions like isAuthorized(),
isAnonymous() & isRole() -->
<security:intercept-url pattern="/user-login"
access="isAnonymous()"/> <!-- To avoid redirect loop since login-page
changed -->
<security:intercept-url pattern="/forms/**"
access="hasRole('ROLE_USER')"/>
<security:intercept-url pattern="/simpleQuestions/**"
access="hasRole('ROLE_USER')"/>
<security:intercept-url pattern="/mcQuestions/**"
access="hasRole('ROLE_USER')"/>
<security:intercept-url pattern="/simpleAnswers/**"
access="hasRole('ROLE_USER')"/>
9 | P a g e
<security:intercept-url pattern="/choiceAnswers/**"
access="hasRole('ROLE_USER')"/>
<security:form-login login-page="/user-login"
default-target-url="/forms"
always-use-default-target="true"
authentication-failure-url="/error-login" />
<security:logout logout-success-url="/forms" />
</security:http>
<!--
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="jimi" password="jimispassword"
authorities="ROLE_USER, ROLE_ADMIN" />
<security:user name="bob" password="bobspassword"
authorities="ROLE_USER" />
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
-->
<security:authentication-manager>
<security:authentication-provider user-service-
ref="customUserDetailsService">
<security:password-encoder hash="sha" />
</security:authentication-provider>
</security:authentication-manager>
</beans>
It seems that this file contains a lot of things, but let’s decompose it and explain
what’s happening.
<context:annotation-config />
<context:component-scan base-package="com.abahhar.formsapp.service"
/>
<jpa:repositories base-package="com.abahhar.formsapp.repository"/>
We have seen this fragment of code in servlet-context.xml, but because of the
decomposition we are making, the Spring Security later will need to inject some
service dependencies for its library, and that won’t work unless we add the following
fragment of code in this file.
10 | P a g e
<!-- Spring Security Configuration -->
<security:http pattern="/resources/**" security="none"/> <!--
Permit access to static resources -->
<security:http auto-config='true' use-expressions="true"> <!-- use-
expressions enables using expressions like isAuthorized(),
isAnonymous() & isRole() -->
<security:intercept-url pattern="/user-login"
access="isAnonymous()"/> <!-- To avoid redirect loop since login-page
changed -->
<security:intercept-url pattern="/forms/**"
access="hasRole('ROLE_USER')"/>
<security:intercept-url pattern="/simpleQuestions/**"
access="hasRole('ROLE_USER')"/>
<security:intercept-url pattern="/mcQuestions/**"
access="hasRole('ROLE_USER')"/>
<security:intercept-url pattern="/simpleAnswers/**"
access="hasRole('ROLE_USER')"/>
<security:intercept-url pattern="/choiceAnswers/**"
access="hasRole('ROLE_USER')"/>
<security:form-login login-page="/user-login"
default-target-url="/forms"
always-use-default-target="true"
authentication-failure-url="/error-login" />
<security:logout logout-success-url="/forms" />
</security:http>
Here we setup the authorization settings, meaning that which links are to be accessed
and which are denied for each role.
First we set the resources folder to be accessible by all, because there is where the
images, CSS and JavaScript files reside.
Second, we set to attributes in the second http tag, auto-config to true, and use-
expressions to true.
Auto-config will make the Spring Security insert default tags and attributes for setting
everything, because there are other things that we do not want to bother ourselves
with, so we let it set it to default values.
Use-expression attribute will enable us to use expressions like “isAnonymous()” and
“hasRole()” in the configuration file and the views later, to be able show the proper
features to proper users.
Intercept-url tag is used to set two things, the URL pattern and the role that is
authorized to access that URL pattern. You can set whatever URL to whatever role
you would like, taking into account that in this application we will have
ROLE_ADMIN and ROLE_USER.
Form-login tag sets the default URL for the login page, the default target URL which
to be directed to after login, the page to be directed to if the login fails and the page to
be directed to after the logout action.
11 | P a g e
The last fragments to discuss are the authentication-manager tag, the commented one
could be used to have in-memory users set up by you as you like, which you could use
in running the application as they were to exist as registered users.
The second and used one, is setup to use the customized user service which we will
setup later, and have the hashing setup to be using sha encryption, you could use other
hashing settings such as “plaintext”, which deals with the password with no
encryption, and “md5”, which uses md5 encryption.
2.6. Web.xml Configuration
The last configuration file to modify is web.xml, which exists in the following
directory:
FormsAppsrcmainwebappWEB-INF
Please make sure that the file contains the following fragment of code:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- The definition of the Root Spring Container shared by all
Servlets and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/root-context.xml,
classpath:datasource.xml,
classpath:spring-security.xml
</param-value>
</context-param>
<!-- Creates the Spring Container shared by all Servlets and
Filters -->
<listener>
<listener-
class>org.springframework.web.context.ContextLoaderListener</listener
-class>
</listener>
<!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-
class>org.springframework.web.servlet.DispatcherServlet</servlet-
class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-
context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
12 | P a g e
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- Spring Security Filters -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-
class>org.springframework.web.filter.DelegatingFilterProxy</filter-
class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
Here we have to things added to the default file, the import of the datasource.xml and
spring-security.xml files in this fragment of code:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/root-context.xml,
classpath:datasource.xml,
classpath:spring-security.xml
</param-value>
</context-param>
And some settings for springSecurityFilterChain that must exist, so that Spring
Security to works:
<!-- Spring Security Filters -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-
class>org.springframework.web.filter.DelegatingFilterProxy</filter-
class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Please note in the first fragment of code, “classpath” evaluates to the directory
“src/main/resources”, which is the package stated that you should include the files in
when explaining setting the configuration files.
13 | P a g e
2.7. Packages
In this tutorial, we setup the project to have the following packages:
1. Com.abahhar.formsapp
2. Com.abahhar.formsapp.controller
3. Com.abahhar.formsapp.domain
4. Com.abahhar.formsapp.repository
5. Com.abahhar.formsapp.service
6. Com.abahhar.formsapp.wrapper
2.8. Static Resources
Static resources such as images, CSS and JavaScript files should exist in the following
directory: “FormsAppsrcmainwebappresources”.
2.9. Class Diagram
This is the class diagram that the web application is based on:
14 | P a g e
2.10. Database Schema
The following is the schema of the database tables that we will be using:
Roles
Role ID Role
Users
User ID Username Password
UsersRoles
User ID Role ID
Forms
Form ID Title
AnsweredForms
User ID Form ID
Questions
Question ID Text Form ID
15 | P a g e
SimpleQuestions
Question ID NumberOfQuestions
MCQuestions
Question ID
Choices
Choice ID Text Question ID
AnsweredSimpleQuestion
SimpleAnswer ID Text Question ID User ID
AnsweredMCQuestion
MCAnswer ID Choice ID Question ID User ID
16 | P a g e
In order to create the database tables in your database, please use the following SQL
statements:
--
-- Table structure for table `choiceanswers`
--
CREATE TABLE `choiceanswers` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`choice_id` int(11) NOT NULL,
`question_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `choice_id` (`choice_id`),
KEY `question_id` (`question_id`),
KEY `user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=13 ;
-- --------------------------------------------------------
--
-- Table structure for table `choices`
--
CREATE TABLE `choices` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`text` varchar(50) NOT NULL,
`question_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `question_id` (`question_id`),
KEY `question_id_2` (`question_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=78 ;
-- --------------------------------------------------------
--
-- Table structure for table `forms`
--
CREATE TABLE `forms` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=8 ;
-- --------------------------------------------------------
--
-- Table structure for table `mcquestions`
--
CREATE TABLE `mcquestions` (
`id` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=47 ;
-- --------------------------------------------------------
--
-- Table structure for table `questions`
17 | P a g e
--
CREATE TABLE `questions` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`text` varchar(50) NOT NULL,
`form_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `form_id` (`form_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=47 ;
-- --------------------------------------------------------
--
-- Table structure for table `roles`
--
CREATE TABLE `roles` (
`id` int(6) NOT NULL AUTO_INCREMENT,
`role` varchar(20) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ;
-- --------------------------------------------------------
--
-- Table structure for table `simpleanswers`
--
CREATE TABLE `simpleanswers` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`text` varchar(50) NOT NULL,
`question_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `question_id` (`question_id`),
KEY `user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=9 ;
-- --------------------------------------------------------
--
-- Table structure for table `simplequestions`
--
CREATE TABLE `simplequestions` (
`id` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=30 ;
-- --------------------------------------------------------
--
-- Table structure for table `users`
--
CREATE TABLE `users` (
`id` int(6) NOT NULL AUTO_INCREMENT,
`login` varchar(20) NOT NULL,
`password` varchar(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=16 ;
18 | P a g e
-- --------------------------------------------------------
--
-- Table structure for table `usersforms`
--
CREATE TABLE `usersforms` (
`user_id` int(11) NOT NULL,
`form_id` int(11) NOT NULL,
PRIMARY KEY (`user_id`,`form_id`),
KEY `form_id` (`form_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT;
-- --------------------------------------------------------
--
-- Table structure for table `user_roles`
--
CREATE TABLE `user_roles` (
`user_id` int(6) NOT NULL,
`role_id` int(6) NOT NULL,
KEY `user` (`user_id`),
KEY `role` (`role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Constraints for dumped tables
--
--
-- Constraints for table `choiceanswers`
--
ALTER TABLE `choiceanswers`
ADD CONSTRAINT `choiceanswers_ibfk_1` FOREIGN KEY (`choice_id`)
REFERENCES `choices` (`id`) ON DELETE CASCADE,
ADD CONSTRAINT `choiceanswers_ibfk_2` FOREIGN KEY (`question_id`)
REFERENCES `mcquestions` (`id`) ON DELETE CASCADE,
ADD CONSTRAINT `choiceanswers_ibfk_3` FOREIGN KEY (`user_id`)
REFERENCES `users` (`id`) ON DELETE CASCADE;
--
-- Constraints for table `choices`
--
ALTER TABLE `choices`
ADD CONSTRAINT `choices_ibfk_1` FOREIGN KEY (`question_id`)
REFERENCES `mcquestions` (`id`) ON DELETE CASCADE;
--
-- Constraints for table `mcquestions`
--
ALTER TABLE `mcquestions`
ADD CONSTRAINT `mcquestions_ibfk_1` FOREIGN KEY (`id`) REFERENCES
`questions` (`id`) ON DELETE CASCADE;
--
-- Constraints for table `questions`
--
ALTER TABLE `questions`
19 | P a g e
ADD CONSTRAINT `questions_ibfk_1` FOREIGN KEY (`form_id`)
REFERENCES `forms` (`id`) ON DELETE CASCADE;
--
-- Constraints for table `simpleanswers`
--
ALTER TABLE `simpleanswers`
ADD CONSTRAINT `simpleanswers_ibfk_1` FOREIGN KEY (`question_id`)
REFERENCES `simplequestions` (`id`) ON DELETE CASCADE,
ADD CONSTRAINT `simpleanswers_ibfk_2` FOREIGN KEY (`user_id`)
REFERENCES `users` (`id`) ON DELETE CASCADE;
--
-- Constraints for table `simplequestions`
--
ALTER TABLE `simplequestions`
ADD CONSTRAINT `simplequestions_ibfk_1` FOREIGN KEY (`id`)
REFERENCES `questions` (`id`) ON DELETE CASCADE;
--
-- Constraints for table `usersforms`
--
ALTER TABLE `usersforms`
ADD CONSTRAINT `usersforms_ibfk_1` FOREIGN KEY (`user_id`)
REFERENCES `users` (`id`) ON DELETE CASCADE,
ADD CONSTRAINT `usersforms_ibfk_2` FOREIGN KEY (`form_id`)
REFERENCES `forms` (`id`) ON DELETE CASCADE;
Also, use the following SQL statements to populate users, roles and user_roles tables:
INSERT INTO `users` (`id`, `login`, `password`) VALUES
(1, 'admin', '3d4f2bf07dc1be38b20cd6e46949a1071f9d0e3d'),
(2, 'user', '273a0c7bd3c679ba9a6f5d99078e36e85d02b952');
INSERT INTO `roles` (`id`, `role`) VALUES
(1, 'admin'),
(2, 'user');
INSERT INTO `user_roles` (`user_id`, `role_id`) VALUES
(1, 1),
(2, 2);
The password for admin is: 111111
The password for user is: 222222
20 | P a g e
3. Models
According to the class diagram, the application will have the following models:
 User
 Role
 Form
 Simple Question
 MC Question
 Choice
 Answered Simple Question
 Answered MC Question
In this section, the code of the models and some explanation of the data annotations
used are to be provided. Please make sure that all the models are to be included in the
package “com.abahhar.formsapp.domain”.
3.1. User
package com.abahhar.formsapp.domain;
import java.util.Set;
import javax.persistence.*;
@Entity
@Table(name="users")
public class User {
@Id
@GeneratedValue
private Integer id;
private String login;
private String password;
//---------------------------------Navigation properties---------
------------------------//
@OneToOne(cascade=CascadeType.ALL)
@JoinTable(name="user_roles",
joinColumns = {@JoinColumn(name="user_id",
referencedColumnName="id")},
inverseJoinColumns = {@JoinColumn(name="role_id",
referencedColumnName="id")}
)
private Role role;
@OneToMany(mappedBy="user", cascade=CascadeType.REMOVE,
fetch=FetchType.EAGER)
private Set<SimpleAnswer> simpleAnswers;
@OneToMany(mappedBy="user", cascade=CascadeType.REMOVE,
fetch=FetchType.EAGER)
private Set<ChoiceAnswer> choiceAnswers;
21 | P a g e
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Role getRole() {
return role;
}
public void setRole(Role role) {
this.role = role;
}
public Set<SimpleAnswer> getSimpleAnswers() {
return simpleAnswers;
}
public void setSimpleAnswers(Set<SimpleAnswer> simpleAnswers) {
this.simpleAnswers = simpleAnswers;
}
public Set<ChoiceAnswer> getChoiceAnswers() {
return choiceAnswers;
}
public void setChoiceAnswers(Set<ChoiceAnswer> choiceAnswers) {
this.choiceAnswers = choiceAnswers;
}
}
22 | P a g e
This is a regular Java class that you would create, the only thing that you might be
concerned about are the data annotations used, and here is an explanation for each:
Data Annotation Description
Entity
Used to declare a class as an entity to be
used in data access
Table
Used to specify the name of the table that
the model is going to be mapped to
Id
Used to specify that an attribute is the
primary key
GeneratedValue
Used to specify that an attribute is
automatically generated
“Auto_Increment”
OneToOne
Used to specify that a property will have
a one to one relationship with another
navigation property. Cascade attribute is
used to specify the type of cascade
JoinTable
Used to specify the name of the table that
will be used to join two tables, in this
model, the table “user_roles” is used to
join the “user” and “role” tables
JoinColumns
Used to specify to map the joined column
with the models properties, in this
example, “user_id” is mapped to the id of
this current class, and “role_id” is
mapped to the id of the Role class, since
the annotations are put above the
navigation property “role”
23 | P a g e
OneToMany
Used to specify that the current class is
having a one-to-many relationship with
another navigation property, the user has
many simple answers and many choice
answers. MappedBy property specifies
which navigation property in the other
end is used for this class, for example,
mappedBy=user, means that
simpleAnswers and choiceAnswers will
have a navigation property called user,
which will be used for this relationship.
Cascade specifies the type of cascade.
Fetch specifies if the fetching is lazy or
eager.
24 | P a g e
3.2. Role
package com.abahhar.formsapp.domain;
import java.util.Set;
import javax.persistence.*;
@Entity
@Table(name="roles")
public class Role {
@Id
@GeneratedValue
private Integer id;
private String role;
//---------------------------------Navigation properties---------
------------------------//
@OneToMany(cascade=CascadeType.ALL)
@JoinTable(name="user_roles",
joinColumns = {@JoinColumn(name="role_id",
referencedColumnName="id")},
inverseJoinColumns = {@JoinColumn(name="user_id",
referencedColumnName="id")}
)
private Set<User> userRoles;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public Set<User> getUserRoles() {
return userRoles;
}
public void setUserRoles(Set<User> userRoles) {
this.userRoles = userRoles;
}
}
25 | P a g e
3.3. Form
package com.abahhar.formsapp.domain;
import java.util.Set;
import javax.persistence.*;
@Entity
@Table(name="forms")
public class Form {
@Id
@GeneratedValue
private Integer id;
@Column
private String title;
public Form(){
}
public Form(String title){
this.title = title;
}
//---------------------------------Navigation properties-------
--------------------------//
@OneToMany(mappedBy="form", cascade=CascadeType.REMOVE,
fetch=FetchType.EAGER)
private Set<Question> questions;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Set<Question> getQuestions() {
return questions;
}
public void setQuestions(Set<Question> questions) {
this.questions = questions;
}
}
26 | P a g e
3.4. Question
package com.abahhar.formsapp.domain;
import javax.persistence.*;
@Entity
@Table(name="questions")
@Inheritance(strategy=InheritanceType.JOINED) //Joined strategy for
table per subclass
public class Question {
@Id
@GeneratedValue
private Integer id;
@Column
private String text;
public Question(){
}
public Question(String text){
this.text = text;
}
//---------------------------------Navigation properties-------
--------------------------//
@ManyToOne
@JoinColumn(name="form_id")
private Form form;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public Form getForm() {
return form;
}
public void setForm(Form form) {
this.form = form;
}
}
27 | P a g e
Since we are using inheritance and we want it to be mapped to the database schema,
@Inheritance data annotation is used to specify the strategy to be used. According to
the database schema, we are using the joined strategy.
To read more about this strategy and other strategies with applied examples, please
refer to the following article:
http://www.dineshonjava.com/p/implementing-inheritance-in-
hibernate.html#.VZuKlRuqqko
Also, @ManyToOne annotation is used for the relationship used between the form
and question. Since Form class contains @OneToMany, meaning one form to many
questions, then in the other side, which is Question class, we annotate the form
navigation property with @ManyToOne, meaning many questions to one form.
@JoinColumn is used to specify the foreign key to be mapped to in the Questions
table, which in this case is form_id, to be used to refer to the form.
3.5. SimpleQuestion
package com.abahhar.formsapp.domain;
import java.util.Set;
import javax.persistence.*;
@Entity
@Table(name="simplequestions")
public class SimpleQuestion extends Question {
public SimpleQuestion(){
super();
}
public SimpleQuestion(String text){
super(text);
}
//---------------------------------Navigation properties-------
--------------------------//
@OneToMany(mappedBy="simpleQuestion",
cascade=CascadeType.REMOVE, fetch=FetchType.EAGER)
private Set<SimpleAnswer> simpleAnswers;
public Set<SimpleAnswer> getSimpleAnswers() {
return simpleAnswers;
}
public void setSimpleAnswers(Set<SimpleAnswer> simpleAnswers) {
this.simpleAnswers = simpleAnswers;
}
}
28 | P a g e
3.6. MCQuestion
package com.abahhar.formsapp.domain;
import java.util.Iterator;
import java.util.Set;
import javax.persistence.*;
@Entity
@Table(name="mcquestions")
public class MCQuestion extends Question {
public MCQuestion(){
super();
}
//---------------------------------Navigation properties-------
--------------------------//
@OneToMany(mappedBy="mcQuestion", cascade=CascadeType.REMOVE,
fetch=FetchType.EAGER)
private Set<Choice> choices;
@OneToMany(mappedBy="mcQuestion", cascade=CascadeType.REMOVE,
fetch=FetchType.EAGER)
private Set<ChoiceAnswer> choiceAnswers;
public Set<Choice> getChoices() {
return choices;
}
public void setChoices(Set<Choice> choices) {
this.choices = choices;
}
public Set<ChoiceAnswer> getChoiceAnswers() {
return choiceAnswers;
}
public void setChoiceAnswers(Set<ChoiceAnswer> choiceAnswers) {
this.choiceAnswers = choiceAnswers;
}
}
29 | P a g e
3.7. Choice
package com.abahhar.formsapp.domain;
import java.util.Set;
import javax.persistence.*;
@Entity
@Table(name="choices")
public class Choice {
@Id
@GeneratedValue
private Integer id;
@Column
private String text;
public Choice(){
}
public Choice(String text){
this.text = text;
}
//---------------------------------Navigation properties-------
--------------------------//
@ManyToOne
@JoinColumn(name="question_id")
private MCQuestion mcQuestion;
@OneToMany(mappedBy="choice", cascade=CascadeType.REMOVE,
fetch=FetchType.EAGER)
private Set<ChoiceAnswer> choiceAnswers;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public MCQuestion getMcQuestion() {
return mcQuestion;
}
public void setMcQuestion(MCQuestion mcQuestion) {
this.mcQuestion = mcQuestion;
}
30 | P a g e
public Set<ChoiceAnswer> getChoiceAnswers() {
return choiceAnswers;
}
public void setChoiceAnswers(Set<ChoiceAnswer> choiceAnswers) {
this.choiceAnswers = choiceAnswers;
}
}
3.8. SimpleAnswer
package com.abahhar.formsapp.domain;
import javax.persistence.*;
@Entity
@Table(name="simpleanswers")
public class SimpleAnswer {
@Id
@GeneratedValue
private Integer id;
@Column
private String text;
public SimpleAnswer(){
}
public SimpleAnswer(String text){
this.text = text;
}
//---------------------------------Navigation properties-------
--------------------------//
@ManyToOne
@JoinColumn(name="question_id")
private SimpleQuestion simpleQuestion;
@ManyToOne
@JoinColumn(name="user_id")
private User user;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getText() {
return text;
}
public void setText(String text) {
31 | P a g e
this.text = text;
}
public SimpleQuestion getSimpleQuestion() {
return simpleQuestion;
}
public void setSimpleQuestion(SimpleQuestion simpleQuestion) {
this.simpleQuestion = simpleQuestion;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
3.9. ChoiceAnswer
package com.abahhar.formsapp.domain;
import javax.persistence.*;
@Entity
@Table(name="choiceanswers")
public class ChoiceAnswer {
@Id
@GeneratedValue
private Integer id;
public ChoiceAnswer(){
}
//---------------------------------Navigation properties-------
--------------------------//
@ManyToOne
@JoinColumn(name="question_id")
private MCQuestion mcQuestion;
@ManyToOne
@JoinColumn(name="choice_id")
private Choice choice;
@ManyToOne
@JoinColumn(name="user_id")
private User user;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
32 | P a g e
}
public MCQuestion getMcQuestion() {
return mcQuestion;
}
public void setMcQuestion(MCQuestion mcQuestion) {
this.mcQuestion = mcQuestion;
}
public Choice getChoice() {
return choice;
}
public void setChoice(Choice choice) {
this.choice = choice;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
33 | P a g e
4. Repositories
In this section, we create interfaces for the repositories that we will be using.
Repositories are used for the data access, this gives us a good separation of the data
access logic so we do not bother ourselves with when writing the logic. Also, all the
interfaces that we will be creating extend a ready interface that is called
JpaRepository, which we specify for it the type that we are dealing with and the type
of its primary key.
JpaRepository includes many built in methods that will help us in inserting, updating
and deleting the entity we are dealing with, which saves our time, because we will not
need to write anything for doing any transaction to the database.
4.1. UserRepository
package com.abahhar.formsapp.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.abahhar.formsapp.domain.User;
public interface UserRepository extends JpaRepository<User, Integer>
{
public User findByLogin(String login);
}
4.2. RoleRepository
package com.abahhar.formsapp.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.abahhar.formsapp.domain.Question;
public interface QuestionRepository<T extends Question>
extends JpaRepository<T, Integer> {
}
4.3. FormRepository
package com.abahhar.formsapp.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.abahhar.formsapp.domain.Form;
public interface FormRepository extends JpaRepository<Form, Integer>
{
}
34 | P a g e
4.4. QuestionRepository
package com.abahhar.formsapp.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.abahhar.formsapp.domain.Question;
public interface QuestionRepository<T extends Question>
extends JpaRepository<T, Integer> {
}
4.5. SimpleQuestionRepository
package com.abahhar.formsapp.repository;
import com.abahhar.formsapp.domain.SimpleQuestion;
public interface SimpleQuestionRepository extends
QuestionRepository<SimpleQuestion> {
}
4.6. MCQuestionRepository
package com.abahhar.formsapp.repository;
import com.abahhar.formsapp.domain.MCQuestion;
public interface MCQuestionRepository extends
QuestionRepository<MCQuestion> {
}
4.7. ChoiceRepository
package com.abahhar.formsapp.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.abahhar.formsapp.domain.Choice;
public interface ChoiceRepository extends JpaRepository<Choice,
Integer> {
}
35 | P a g e
4.8. SimpleAnswerRepository
package com.abahhar.formsapp.repository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import com.abahhar.formsapp.domain.SimpleAnswer;
import com.abahhar.formsapp.domain.SimpleQuestion;
import com.abahhar.formsapp.domain.User;
public interface SimpleAnswerRepository extends
JpaRepository<SimpleAnswer, Integer> {
}
4.9. ChoiceAnswerRepository
package com.abahhar.formsapp.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.abahhar.formsapp.domain.ChoiceAnswer;
public interface ChoiceAnswerRepository extends
JpaRepository<ChoiceAnswer, Integer> {
}
5. Services
In this section, we create the needed services to be used in the application. Services
provide us a good separation of the business logic that we need. Controllers use the
services, and the services use repositories, and with this we have a good separation of
concerns.
Please make sure that the services are in “com.abahhar.formsapp.service” package.
5.1. CustomUserDetailsService
package com.abahhar.formsapp.service;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import
org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import
org.springframework.security.core.userdetails.UserDetailsService;
36 | P a g e
import
org.springframework.security.core.userdetails.UsernameNotFoundExcepti
on;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.abahhar.formsapp.repository.UserRepository;
@Service
@Transactional(readOnly=true)
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
public UserDetails loadUserByUsername(String login)
throws UsernameNotFoundException {
com.abahhar.formsapp.domain.User domainUser =
userRepository.findByLogin(login);
boolean enabled = true;
boolean accountNonExpired = true;
boolean credentialsNonExpired = true;
boolean accountNonLocked = true;
return new User(
domainUser.getLogin(),
domainUser.getPassword(),
enabled,
accountNonExpired,
credentialsNonExpired,
accountNonLocked,
getAuthorities(domainUser.getRole().getId())
);
}
public Collection<? extends GrantedAuthority>
getAuthorities(Integer role) {
List<GrantedAuthority> authList =
getGrantedAuthorities(getRoles(role));
return authList;
}
public List<String> getRoles(Integer role) {
List<String> roles = new ArrayList<String>();
if (role.intValue() == 1) {
roles.add("ROLE_USER");
roles.add("ROLE_ADMIN");
} else if (role.intValue() == 2) {
roles.add("ROLE_USER");
}
return roles;
}
public static List<GrantedAuthority>
getGrantedAuthorities(List<String> roles) {
List<GrantedAuthority> authorities = new
ArrayList<GrantedAuthority>();
37 | P a g e
for (String role : roles) {
authorities.add(new SimpleGrantedAuthority(role));
}
return authorities;
}
}
This service will be used by Spring Security to do everything about authentication and
authorization with respect to the database. Also, it is the one specified in the spring-
security.xml configuration in the fragment of code:
<security:authentication-manager>
<security:authentication-provider user-service-
ref="customUserDetailsService">
<security:password-encoder hash="sha" />
</security:authentication-provider>
</security:authentication-manager>
Notice that the service is annotated with @Service annotations, to declare it as a
Spring Component, and it will be scanned for dependency injection.
Furthermore, @Transactional annotation is used. For information about this
annotation, please refer to the following link:
http://stackoverflow.com/questions/15300483/some-clarification-about-spring-
transactional-annotation-on-a-method
38 | P a g e
5.2. UserService
package com.abahhar.formsapp.service;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.abahhar.formsapp.domain.Role;
import com.abahhar.formsapp.domain.User;
import com.abahhar.formsapp.repository.RoleRepository;
import com.abahhar.formsapp.repository.UserRepository;
@Service
@Transactional
public class UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private RoleRepository roleRepository;
public User getUser(String login){
return userRepository.findByLogin(login);
}
public boolean registerUser(User user){
User loadedUser =
userRepository.findByLogin(user.getLogin());
if(loadedUser != null){
return false;
}
String hashedPassword =
DigestUtils.sha1Hex(user.getPassword());
Role role = roleRepository.findOne(2);
List<User> usersList = userRepository.findAll();
Set<User> userRoles = new HashSet<User>();
Iterator<User> iterator = usersList.iterator();
while(iterator.hasNext()){
User userRole = iterator.next();
//The admin doesn't need to have the ROLE_USER,
only users
if(userRole.getRole().getId() != 1){
userRoles.add(userRole);
}
}
userRoles.add(user);
role.setUserRoles(userRoles);
39 | P a g e
user.setPassword(hashedPassword);
roleRepository.save(role);
return true;
}
}
This service is what we will use in the controllers to deal with users, as you notice, we
use two repositories here which are: UserRepository and RoleRepository. The
repositories are automatically injected by the framework since annotated with
@Autowired.
Also, we have two methods: getUser, which retrieves for us a user by his username,
and registerUser, which registers a user.
Please notice that in the registerUser we encrypt the password with sha1 encryption,
and we add the user role for the registered user, then save it in the database using the
repository.
5.3. RoleService
package com.abahhar.formsapp.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.abahhar.formsapp.domain.Role;
import com.abahhar.formsapp.repository.RoleRepository;
@Service
@Transactional
public class RoleService {
@Autowired
private RoleRepository roleRepository;
public Role getRole(int id){
return roleRepository.findOne(id);
}
}
40 | P a g e
5.4. FormService
package com.abahhar.formsapp.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.abahhar.formsapp.domain.Form;
import com.abahhar.formsapp.repository.FormRepository;
@Service
@Transactional
public class FormService {
@Autowired
private FormRepository formRepository;
public Iterable<Form> findAll() {
return formRepository.findAll();
}
public Form save(Form entity) {
return formRepository.save(entity);
}
public void delete(Integer id) {
formRepository.delete(id);
}
public Form findOne(Integer id) {
return formRepository.findOne(id);
}
}
5.5. SimpleQuestionService
package com.abahhar.formsapp.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.abahhar.formsapp.domain.SimpleQuestion;
import com.abahhar.formsapp.repository.SimpleQuestionRepository;
@Service
@Transactional
public class SimpleQuestionService {
@Autowired
private SimpleQuestionRepository simpleQuestionRepository;
public Iterable<SimpleQuestion> findAll() {
return simpleQuestionRepository.findAll();
}
public SimpleQuestion save(SimpleQuestion entity) {
return simpleQuestionRepository.save(entity);
41 | P a g e
}
public void delete(Integer id) {
simpleQuestionRepository.delete(id);
}
public SimpleQuestion findOne(Integer id) {
return simpleQuestionRepository.findOne(id);
}
}
5.6. MCQuestionService
package com.abahhar.formsapp.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.abahhar.formsapp.domain.MCQuestion;
import com.abahhar.formsapp.repository.MCQuestionRepository;
@Service
@Transactional
public class MCQuestionService {
@Autowired
private MCQuestionRepository mcQuestionRepository;
public Iterable<MCQuestion> findAll() {
return mcQuestionRepository.findAll();
}
public MCQuestion save(MCQuestion entity) {
return mcQuestionRepository.save(entity);
}
public void delete(Integer id) {
mcQuestionRepository.delete(id);
}
public MCQuestion findOne(Integer id) {
return mcQuestionRepository.findOne(id);
}
}
42 | P a g e
5.7. ChoiceService
package com.abahhar.formsapp.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.abahhar.formsapp.domain.Choice;
import com.abahhar.formsapp.repository.ChoiceRepository;
@Service
@Transactional
public class ChoiceService {
@Autowired
private ChoiceRepository choiceRepository;
public Iterable<Choice> findAll() {
return choiceRepository.findAll();
}
public Choice save(Choice entity) {
return choiceRepository.save(entity);
}
public void delete(Integer id) {
choiceRepository.delete(id);
}
public Choice findOne(Integer id) {
return choiceRepository.findOne(id);
}
}
5.8. SimpleAnswerService
package com.abahhar.formsapp.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.abahhar.formsapp.domain.SimpleAnswer;
import com.abahhar.formsapp.domain.SimpleQuestion;
import com.abahhar.formsapp.domain.User;
import com.abahhar.formsapp.repository.SimpleAnswerRepository;
@Service
@Transactional
public class SimpleAnswerService {
@Autowired
private SimpleAnswerRepository simpleAnswerRepository;
public Iterable<SimpleAnswer> findAll() {
return simpleAnswerRepository.findAll();
43 | P a g e
}
public SimpleAnswer save(SimpleAnswer entity) {
return simpleAnswerRepository.save(entity);
}
public void delete(Integer id) {
simpleAnswerRepository.delete(id);
}
public SimpleAnswer findOne(Integer id) {
return simpleAnswerRepository.findOne(id);
}
}
5.9. ChoiceAnswerService
package com.abahhar.formsapp.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.abahhar.formsapp.domain.ChoiceAnswer;
import com.abahhar.formsapp.repository.ChoiceAnswerRepository;
@Service
@Transactional
public class ChoiceAnswerService {
@Autowired
private ChoiceAnswerRepository choiceAnswerRepository;
public Iterable<ChoiceAnswer> findAll() {
return choiceAnswerRepository.findAll();
}
public ChoiceAnswer save(ChoiceAnswer entity) {
return choiceAnswerRepository.save(entity);
}
public void delete(Integer id) {
choiceAnswerRepository.delete(id);
}
public ChoiceAnswer findOne(Integer id) {
return choiceAnswerRepository.findOne(id);
}
}
44 | P a g e
6. MCQuestion Wrapper Class
MCQuestionWrapper is a wrapper class that we will be using later in
MCQuestionController, to avoid any errors later, please make sure that this class exist
in “com.abahhar.formsapp.wrapper” package.
This class wraps an MCQuestion with the list of choices.
package com.abahhar.formsapp.wrapper;
import java.util.ArrayList;
import java.util.List;
import com.abahhar.formsapp.domain.Choice;
import com.abahhar.formsapp.domain.Form;
import com.abahhar.formsapp.domain.MCQuestion;
public class MCQuestionWrapper {
private MCQuestion mcQuestion;
private List<Choice> choices;
public MCQuestionWrapper(){
this.mcQuestion = new MCQuestion();
this.choices = new ArrayList<Choice>();
}
public MCQuestion getMcQuestion() {
return mcQuestion;
}
public void setMcQuestion(MCQuestion mcQuestion) {
this.mcQuestion = mcQuestion;
}
public List<Choice> getChoices() {
return choices;
}
public void setChoices(List<Choice> choices) {
this.choices = choices;
}
}
45 | P a g e
7. Controllers
In this section, we create the proper controllers for the web application with proper
actions.
Please make sure that the controllers are in “com.abahhar.formsapp.controller”
package, except for HomeController, which is in “com.abahhar.formsapp” package.
7.1. Home Controller
package com.abahhar.formsapp;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
/**
* Handles requests for the application home page.
*/
@Controller
public class HomeController {
/**
* Simply selects the home view to render by returning its
name.
*/
@RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView home() {
return new ModelAndView("redirect:/forms");
}
}
This controller contains the action home(), which you could access by going to URL
localhost/. The mapping of the URL to the action is specified by the value attribute in
the data annotation @RequestMapping, and the method specified is GET method.
This action redirects the user to “localhost/forms”. As you notice, the action returns
ModelAndView, which is a type that enables you to specify the path for the view to
return to, and enables you to include models and data to be returned to the view.
Another thing to notice is that if you want the Spring Framework to know that the
class is a Spring Controller “Component”, then you must put @Controller annotation
on the controller as done in this fragment of code, and you will notice in the package
explorer, the icon of the file will have a blue S on it, which means that this is a Spring
Component.
46 | P a g e
7.2. SecurityNavigation Controller
This controller will handle the navigation for login, success-login and logout actions,
because we are using Spring MVC, we should make the controller with URL
mappings to the desired procedures, and this is what we are doing here:
package com.abahhar.formsapp.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import com.abahhar.formsapp.domain.User;
import com.abahhar.formsapp.service.UserService;
@Controller
public class SecurityNavigation {
@Autowired
UserService userService;
@RequestMapping(value="/user-login", method=RequestMethod.GET)
public ModelAndView loginForm() {
return new ModelAndView("login-form");
}
@RequestMapping(value="/error-login", method=RequestMethod.GET)
public ModelAndView invalidLogin() {
ModelAndView modelAndView = new ModelAndView("login-form");
modelAndView.addObject("error", true);
return modelAndView;
}
@RequestMapping(value="/success-login", method=RequestMethod.GET)
public ModelAndView successLogin() {
return new ModelAndView("success-login");
}
@RequestMapping(value="/users/register",
method=RequestMethod.GET)
public ModelAndView register(){
return new ModelAndView("users/register");
}
@RequestMapping(value="/users/register",
method=RequestMethod.POST)
public ModelAndView register(@ModelAttribute("user") User use
if(!userService.registerUser(user)){
return new
ModelAndView("users/register").addObject("error", true);
}
return new ModelAndView("login-form").addObject("registered",
true);}
}
As you notice, the controller contains proper actions for login, success-login, logout
and register. Also, you notice that we have UserService which is annotated with
@Autowired.
@ModelAttribute is used to set the name of the entity that is got from the form in the
view, the name of the entity should be contained in the name attribute of the form tag.
47 | P a g e
7.3. FormsController
package com.abahhar.formsapp.controller;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import com.abahhar.formsapp.domain.Form;
import com.abahhar.formsapp.domain.MCQuestion;
import com.abahhar.formsapp.domain.Question;
import com.abahhar.formsapp.domain.SimpleQuestion;
import com.abahhar.formsapp.service.FormService;
@Controller
public class FormsController {
@Autowired
private FormService formService;
@RequestMapping(value="/forms", method=RequestMethod.GET)
public ModelAndView index(){
ModelAndView modelAndView = new
ModelAndView("forms/index");
modelAndView.addObject("forms", formService.findAll());
return modelAndView;
}
@RequestMapping(value="/forms/details",
method=RequestMethod.GET)
public ModelAndView details(@RequestParam Integer id){
ModelAndView modelAndView = new
ModelAndView("forms/details");
Form form = formService.findOne(id);
Set<SimpleQuestion> simpleQuestions = new
HashSet<SimpleQuestion>();
Set<MCQuestion> mcQuestions = new HashSet<MCQuestion>();
Iterator<Question> iterator =
form.getQuestions().iterator();
while(iterator.hasNext()){
Question question = iterator.next();
if(question instanceof SimpleQuestion){
SimpleQuestion simpleQuestion =
(SimpleQuestion) question;
simpleQuestions.add(simpleQuestion);
}else{
MCQuestion mcQuestion = (MCQuestion)
question;
48 | P a g e
mcQuestions.add(mcQuestion);
}
}
modelAndView.addObject("form", formService.findOne(id));
modelAndView.addObject("simpleQuestions",
simpleQuestions);
modelAndView.addObject("mcQuestions", mcQuestions);
return modelAndView;
}
@RequestMapping(value="/forms/create",
method=RequestMethod.GET)
public String create(){
return "forms/create";
}
@RequestMapping(value="/forms/create",
method=RequestMethod.POST)
@ResponseBody
public ModelAndView create(@ModelAttribute("form") Form form){
formService.save(form);
return new ModelAndView("redirect:/forms");
}
@RequestMapping(value="/forms/update",
method=RequestMethod.GET)
public ModelAndView update(@RequestParam Integer id){
ModelAndView modelAndView = new
ModelAndView("forms/edit");
modelAndView.addObject("form", formService.findOne(id));
return modelAndView;
}
@RequestMapping(value="/forms/update",
method=RequestMethod.POST)
public ModelAndView update(@ModelAttribute("form") Form form){
ModelAndView modelAndView = new
ModelAndView("redirect:/forms/details?id="+form.getId().toString());
formService.save(form);
return modelAndView;
}
@RequestMapping(value="/forms/delete",
method=RequestMethod.GET)
public ModelAndView delete(@RequestParam Integer id){
ModelAndView modelAndView = new
ModelAndView("redirect:/forms");
formService.delete(id);
return modelAndView;
}
}
49 | P a g e
The new thing here is @RequestParam annotation, this is used to specify that a
variable is got from the string parameters (e.g. /forms/update?id=1).
Another thing to notice is that when inserting and updating an entity, we use the save
method from the service. The save method could insert and update at the same time
because of the id of the entity, if the id doesn’t exist in the table, then the entity is new
and will be inserted, but if the id exists, it will update the existed one. All this is
handled automatically in the repository.
7.4. SimpleQuestionsController
package com.abahhar.formsapp.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import com.abahhar.formsapp.domain.Form;
import com.abahhar.formsapp.domain.SimpleQuestion;
import com.abahhar.formsapp.service.FormService;
import com.abahhar.formsapp.service.SimpleQuestionService;
@Controller
public class SimpleQuestionsController {
@Autowired
private SimpleQuestionService simpleQuestionService;
@Autowired
private FormService formService;
@RequestMapping(value="/simpleQuestions/details",
method=RequestMethod.GET)
public ModelAndView details(@RequestParam Integer id){
ModelAndView modelAndView = new
ModelAndView("simpleQuestions/details");
modelAndView.addObject("simpleQuestion",
simpleQuestionService.findOne(id));
return modelAndView;
}
@RequestMapping(value="/simpleQuestions/create",
method=RequestMethod.GET)
public ModelAndView create(@RequestParam Integer formId){
ModelAndView modelAndView = new
ModelAndView("simpleQuestions/create");
modelAndView.addObject("form",
formService.findOne(formId));
return modelAndView;
}
50 | P a g e
@RequestMapping(value="/simpleQuestions/create",
method=RequestMethod.POST)
@ResponseBody
public ModelAndView create(@ModelAttribute("simpleQuestion")
SimpleQuestion simpleQuestion){
simpleQuestionService.save(simpleQuestion);
return new
ModelAndView("redirect:/forms/details?id="+simpleQuestion.getForm().g
etId().toString());
}
@RequestMapping(value="/simpleQuestions/update",
method=RequestMethod.GET)
public ModelAndView update(@RequestParam Integer id){
ModelAndView modelAndView = new
ModelAndView("simpleQuestions/edit");
modelAndView.addObject("simpleQuestion",
simpleQuestionService.findOne(id));
return modelAndView;
}
@RequestMapping(value="/simpleQuestions/update",
method=RequestMethod.POST)
public ModelAndView update(@ModelAttribute("simpleQuestion")
SimpleQuestion simpleQuestion){
simpleQuestion =
simpleQuestionService.save(simpleQuestion);
ModelAndView modelAndView = new
ModelAndView("redirect:/forms/details?id="+simpleQuestion.getForm().g
etId().toString());
return modelAndView;
}
@RequestMapping(value="/simpleQuestions/delete",
method=RequestMethod.GET)
public ModelAndView delete(@RequestParam Integer id){
Integer formId =
simpleQuestionService.findOne(id).getForm().getId();
ModelAndView modelAndView = new
ModelAndView("redirect:/forms/details?id="+formId.toString());
simpleQuestionService.delete(id);
return modelAndView;
}
}
51 | P a g e
7.5. MCQuestionsController
package com.abahhar.formsapp.controller;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import com.abahhar.formsapp.domain.Choice;
import com.abahhar.formsapp.domain.Form;
import com.abahhar.formsapp.domain.MCQuestion;
import com.abahhar.formsapp.domain.SimpleQuestion;
import com.abahhar.formsapp.service.ChoiceService;
import com.abahhar.formsapp.service.FormService;
import com.abahhar.formsapp.service.MCQuestionService;
import com.abahhar.formsapp.wrapper.MCQuestionWrapper;
@Controller
public class MCQuestionsController {
@Autowired
private MCQuestionService mcQuestionService;
@Autowired
private ChoiceService choiceService;
@Autowired
private FormService formService;
@RequestMapping(value="/mcQuestions/details",
method=RequestMethod.GET)
public ModelAndView details(@RequestParam Integer id){
ModelAndView modelAndView = new
ModelAndView("mcQuestions/details");
modelAndView.addObject("mcQuestion",
mcQuestionService.findOne(id));
return modelAndView;
}
@RequestMapping(value="/mcQuestions/create",
method=RequestMethod.GET)
public ModelAndView create(@RequestParam Integer formId){
ModelAndView modelAndView = new
ModelAndView("mcQuestions/create");
MCQuestionWrapper mcQuestionWrapper = new
MCQuestionWrapper();
//add 4 choices to be filled
for(int i = 1; i <= 4; i++){
mcQuestionWrapper.getChoices().add(new Choice());
52 | P a g e
}
modelAndView.addObject("form",
formService.findOne(formId));
modelAndView.addObject("mcQuestionWrapper",
mcQuestionWrapper);
return modelAndView;
}
@RequestMapping(value="/mcQuestions/create",
method=RequestMethod.POST)
@ResponseBody
public ModelAndView create(@ModelAttribute("mcQuestionWrapper")
MCQuestionWrapper mcQuestionWrapper){
MCQuestion mcQuestion =
mcQuestionWrapper.getMcQuestion();
List<Choice> choices = mcQuestionWrapper.getChoices();
mcQuestionService.save(mcQuestion);
Iterator<Choice> iterator = choices.iterator();
while(iterator.hasNext()){
Choice choice = iterator.next();
choice.setMcQuestion(mcQuestion);
choiceService.save(choice);
}
return new
ModelAndView("redirect:/forms/details?id="+mcQuestion.getForm().getId
().toString());
}
@RequestMapping(value="/mcQuestions/update",
method=RequestMethod.GET)
public ModelAndView update(@RequestParam Integer id){
ModelAndView modelAndView = new
ModelAndView("mcQuestions/edit");
MCQuestionWrapper mcQuestionWrapper = new
MCQuestionWrapper();
MCQuestion mcQuestion = mcQuestionService.findOne(id);
mcQuestionWrapper.setMcQuestion(mcQuestion);
Set<Choice> choices = mcQuestion.getChoices();
List<Choice> choicesList = new ArrayList<Choice>();
for(Iterator<Choice> iterator = choices.iterator();
iterator.hasNext(); ){
choicesList.add(iterator.next());
}
mcQuestionWrapper.setChoices(choicesList);
modelAndView.addObject("mcQuestionWrapper",
mcQuestionWrapper);
return modelAndView;
}
53 | P a g e
@RequestMapping(value="/mcQuestions/update",
method=RequestMethod.POST)
public ModelAndView update(@ModelAttribute("mcQuestionWrapper")
MCQuestionWrapper mcQuestionWrapper){
MCQuestion mcQuestion =
mcQuestionWrapper.getMcQuestion();
List<Choice> choices = mcQuestionWrapper.getChoices();
mcQuestionService.save(mcQuestion);
mcQuestion =
mcQuestionService.findOne(mcQuestion.getId());
Iterator<Choice> iterator =
mcQuestion.getChoices().iterator();
while(iterator.hasNext()){
Integer choiceId = iterator.next().getId();
choiceService.delete(choiceId);
}
iterator = choices.iterator();
while(iterator.hasNext()){
Choice choice = iterator.next();
choice.setMcQuestion(mcQuestion);
choiceService.save(choice);
}
return new
ModelAndView("redirect:/forms/details?id="+mcQuestion.getForm().getId
().toString());
}
@RequestMapping(value="/mcQuestions/delete",
method=RequestMethod.GET)
public ModelAndView delete(@RequestParam Integer id){
Integer formId =
mcQuestionService.findOne(id).getForm().getId();
ModelAndView modelAndView = new
ModelAndView("redirect:/forms/details?id="+formId.toString());
mcQuestionService.delete(id);
return modelAndView;
}
}
54 | P a g e
7.6. SimpleAnswerController
package com.abahhar.formsapp.controller;
import org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import com.abahhar.formsapp.domain.SimpleAnswer;
import com.abahhar.formsapp.domain.SimpleQuestion;
import com.abahhar.formsapp.domain.User;
import com.abahhar.formsapp.service.SimpleAnswerService;
import com.abahhar.formsapp.service.SimpleQuestionService;
import com.abahhar.formsapp.service.UserService;
@Controller
public class SimpleAnswersController {
@Autowired
private SimpleAnswerService simpleAnswerService;
@Autowired
private SimpleQuestionService simpleQuestionService;
@Autowired
UserService userService;
@RequestMapping(value="/simpleAnswers/create",
method=RequestMethod.POST)
@ResponseBody
public ModelAndView create(@ModelAttribute("simpleAnswer")
SimpleAnswer simpleAnswer){
ModelAndView modelAndView = new
ModelAndView("redirect:/simpleQuestions/details?id="+simpleAnswer.get
SimpleQuestion().getId().toString());
String login =
SecurityContextHolder.getContext().getAuthentication().getName();
User user = userService.getUser(login);
simpleAnswer.setUser(user);
SimpleQuestion simpleQuestion =
simpleQuestionService.findOne(simpleAnswer.getSimpleQuestion().getId(
));
simpleAnswer.setSimpleQuestion(simpleQuestion);
simpleAnswerService.save(simpleAnswer);
return modelAndView;
}
@RequestMapping(value="/simpleAnswers/delete",
method=RequestMethod.GET)
55 | P a g e
public ModelAndView delete(@RequestParam Integer answerId,
@RequestParam Integer questionId){
ModelAndView modelAndView = new
ModelAndView("redirect:/simpleQuestions/details?id="+questionId);
simpleAnswerService.delete(answerId);
return modelAndView;
}
}
The new thing here is that we are using the following statement to get the username of
the current user:
String login =
SecurityContextHolder.getContext().getAuthentication().getName();
Which with we get the entity of the user and set it to the simple answer, and because
of this assignment, the foreign key of the user id is set automatically after saving the
simple answer.
7.7. ChoiceAnswerController
package com.abahhar.formsapp.controller;
import org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import com.abahhar.formsapp.domain.ChoiceAnswer;
import com.abahhar.formsapp.domain.MCQuestion;
import com.abahhar.formsapp.domain.User;
import com.abahhar.formsapp.service.ChoiceAnswerService;
import com.abahhar.formsapp.service.MCQuestionService;
import com.abahhar.formsapp.service.UserService;
@Controller
public class ChoiceAnswersController {
@Autowired
private ChoiceAnswerService choiceAnswerService;
@Autowired
private MCQuestionService mcQuestionService;
@Autowired
UserService userService;
56 | P a g e
@RequestMapping(value="/choiceAnswers/create",
method=RequestMethod.POST)
@ResponseBody
public ModelAndView create(@ModelAttribute("choiceAnswer")
ChoiceAnswer choiceAnswer){
ModelAndView modelAndView = new
ModelAndView("redirect:/mcQuestions/details?id="+choiceAnswer.getMcQu
estion().getId().toString());
String login =
SecurityContextHolder.getContext().getAuthentication().getName();
User user = userService.getUser(login);
choiceAnswer.setUser(user);
MCQuestion mcQuestion =
mcQuestionService.findOne(choiceAnswer.getMcQuestion().getId());
choiceAnswer.setMcQuestion(mcQuestion);
choiceAnswerService.save(choiceAnswer);
return modelAndView;
}
@RequestMapping(value="/choiceAnswers/delete",
method=RequestMethod.GET)
public ModelAndView delete(@RequestParam Integer answerId,
@RequestParam Integer questionId){
ModelAndView modelAndView = new
ModelAndView("redirect:/mcQuestions/details?id="+questionId);
choiceAnswerService.delete(answerId);
return modelAndView;
}
}
57 | P a g e
8. Views
8.1. login-form.jsp
<div class="container">
<h2 class="text-center">Login</h2>
<c:if test="${error == true}">
<p>
<b class="text-danger">Invalid login or
password.</b>
</p>
</c:if>
<c:if test="${registered == true}">
<p>
<b class="text-success">Successfully
registered, please enter credentials to login.</b>
</p>
</c:if>
<form class="form-horizontal" role="form" method="POST"
action="<c:url value="/j_spring_security_check"/>" >
<div class="form-group">
<label class="control-label col-sm-2"
for="j_username">Username:</label>
<div class="col-sm-10">
<input type="text" class="form-control"
name="j_username" id="j_username" placeholder="Enter username"
autofocus>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2"
for="j_password">Password:</label>
<div class="col-sm-10">
<input type="password" class="form-control"
name="j_password" id="j_password" placeholder="Enter password">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-
default">Login</button>
</div>
</div>
</form>
Here we have two if statements, one to check the value of error, and the other to
check the value of registered. These two values are returned from the controller
through the statements with the following signature
“modelAndView.addObject(“NameOfVariable”, valueOfVariable)”.
If the if statement is satisfied, the content inside the tag will be written in the output.
<c:url /> tag is used to evaluate a statement that contains the current URL, followed
by the value of the “value” attribute.
58 | P a g e
Please notice that “j_username” and “j_password” are the names of variables that
Spring Security deal with when passing the arguments from the views.
8.2. Users
8.2.1. Register.jsp
<div class="container">
<h2 class="text-center">Registration form</h2>
<c:if test="${error == true}">
<p>
<b class="text-danger">Username already
exists.</b>
</p>
</c:if>
<form class="form-horizontal" role="form" name="user"
method="POST" action="<c:url value="/users/register"/>" >
<div class="form-group">
<label class="control-label col-sm-2"
for="login">Username:</label>
<div class="col-sm-10">
<input type="text" class="form-control"
name="login" id="login" placeholder="Enter username" autofocus>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2"
for="password">Password:</label>
<div class="col-sm-10">
<input type="password" class="form-control"
name="password" id="password" placeholder="Enter password">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-
default">Register</button>
</div>
</div>
</form>
59 | P a g e
8.3. Forms
8.3.1. index.jsp
<sec:authorize access="hasRole('ROLE_ADMIN')">
<p>
<a href="<c:url value="/forms/create"/>"
class="btn btn-default btn-lg">Create form</a>
</p>
</sec:authorize>
<!-- Title -->
<div class="row">
<div class="col-lg-12">
<h3>Latest Forms</h3>
</div>
</div>
<!-- /.row -->
<c:choose>
<c:when test="${not empty forms }">
<!-- Page Features -->
<div class="row text-center">
<c:forEach var="form" items="${forms}">
<a href="<c:url
value="forms/details?id=${form.id}" />">
<div class="col-md-3 col-sm-6 hero-
feature">
<div class="thumbnail">
<img src="<c:url
value="/resources/img/form-icon.png" />" alt="">
<div class="caption">
<h3>${form.title}</h3>
<sec:authorize
access="hasRole('ROLE_ADMIN')">
<p>
<a href="<c:url
value="forms/update?id=${form.id}"/>" class="btn btn-
primary">Edit</a> <a href="<c:url
value="forms/delete?id=${form.id}"/>" class="btn btn-
default">Delete</a>
</p>
</sec:authorize>
</div>
</div>
</div>
</a>
</c:forEach>
</div>
<!-- /.row -->
</c:when>
<c:otherwise>
There are no forms
</c:otherwise>
</c:choose>
60 | P a g e
Here we checked the role of the user using the tag <sec:authorize>, we check if the
user is with the role of admin, if the check is satisfied, the button for creating a form
will be displayed in the output.
Also, we used the tags <c:choose>, <c:when> and <c:otherwise>. When using the
choose tag, when will behave as an if statement with the condition in the test attribute,
and otherwise will behave as an else if the condition in the when tag is not satisfied.
Furthermore, we use the tag <c:foreach> to loop through the list of forms we have got
from the controller, we set each item in the list of forms to a variable which we called
“form”, then we used the properties of the form to display them in the page.
Please notice that to access the properties of an object in JSP pages, we include the
name of the property in ${} (e.g. ${form.title}).
Also, to use the authorize tag you should include this fragment of code after the
declaration of the xml file <?xml version=”1.0” encoding=”UTF-9”?>:
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
61 | P a g e
8.3.2. details.jsp
<div class="container">
<h2 class="text-center">${form.title}</h2>
<h4>
<a href="<c:url value="/forms"/>">Back to forms</a>
</h4>
<sec:authorize access="hasRole('ROLE_ADMIN')">
<p>
<a href="<c:url
value="/simpleQuestions/create?formId=${form.id}"/>" class="btn btn-
default btn-lg">Create simple question</a>
<a href="<c:url
value="/mcQuestions/create?formId=${form.id}"/>" class="btn btn-
default btn-lg">Create multiple choice question</a>
</p>
</sec:authorize>
<c:choose>
<c:when test="${not empty simpleQuestions}">
<table class="table table-striped
table-bordered" style="font-size: 18px">
<thead>
<tr>
<th>Simple questions</th>
<sec:authorize
access="hasRole('ROLE_ADMIN')">
<th colspan="2" class="text-
center">Manage</th>
</sec:authorize>
</tr>
</thead>
<tbody>
<c:forEach var="simpleQuestion"
items="${simpleQuestions}">
<tr>
<td style="padding: 10px">
<a href="<c:url
value="../simpleQuestions/details?id=${simpleQuestion.id}" />" >
${simpleQuestion.text}
</a>
</td>
<sec:authorize
access="hasRole('ROLE_ADMIN')">
<td class="text-center">
<a href="<c:url
value="../simpleQuestions/update?id=${simpleQuestion.id}" />" >
Edit
</a>
</td>
<td class="text-center">
<a href="<c:url
value="../simpleQuestions/delete?id=${simpleQuestion.id}" />" >
Delete
</a>
</td>
</sec:authorize>
</tr>
62 | P a g e
</c:forEach>
</tbody>
</table>
</c:when>
<c:otherwise>
<div class="well">
There are no written questions
</div>
</c:otherwise>
</c:choose>
<c:choose>
<c:when test="${not empty mcQuestions}">
<table class="table table-striped
table-bordered" style="font-size: 18px">
<thead>
<tr>
<th>Multiple choice questions</th>
<sec:authorize
access="hasRole('ROLE_ADMIN')">
<th colspan="2" class="text-
center">Manage</th>
</sec:authorize>
</tr>
</thead>
<tbody>
<c:forEach var="mcQuestion"
items="${mcQuestions}">
<tr>
<td style="padding: 10px">
<a href="<c:url
value="../mcQuestions/details?id=${mcQuestion.id}" />" >
${mcQuestion.text}
</a>
</td>
<sec:authorize
access="hasRole('ROLE_ADMIN')">
<td class="text-center">
<a href="<c:url
value="../mcQuestions/update?id=${mcQuestion.id}" />" >
Edit
</a>
</td>
<td class="text-center">
<a href="<c:url
value="../mcQuestions/delete?id=${mcQuestion.id}" />" >
Delete
</a>
</td>
</sec:authorize>
</tr>
</c:forEach>
</tbody>
</table>
</c:when>
<c:otherwise>
<div class="well">
There are no multiple choice questions
IndieLabs-FormsApp Using Spring Framework
IndieLabs-FormsApp Using Spring Framework
IndieLabs-FormsApp Using Spring Framework
IndieLabs-FormsApp Using Spring Framework
IndieLabs-FormsApp Using Spring Framework
IndieLabs-FormsApp Using Spring Framework
IndieLabs-FormsApp Using Spring Framework
IndieLabs-FormsApp Using Spring Framework
IndieLabs-FormsApp Using Spring Framework
IndieLabs-FormsApp Using Spring Framework
IndieLabs-FormsApp Using Spring Framework
IndieLabs-FormsApp Using Spring Framework

More Related Content

What's hot

Android based crime manage system industrial project i
Android based crime manage system industrial project iAndroid based crime manage system industrial project i
Android based crime manage system industrial project i
Beresa Abebe
 
Android based crime manage system industrial project i
Android based crime manage system industrial project iAndroid based crime manage system industrial project i
Android based crime manage system industrial project i
Beresa Abebe
 
bi-foundation-suite-wp-215243
bi-foundation-suite-wp-215243bi-foundation-suite-wp-215243
bi-foundation-suite-wp-215243
David Crotty
 
Dassault Aviation - Company Profile
Dassault Aviation - Company ProfileDassault Aviation - Company Profile
Dassault Aviation - Company Profile
Misovsky2013
 
BR100 Oracle AP Setup
BR100 Oracle AP SetupBR100 Oracle AP Setup
BR100 Oracle AP Setup
Baker Khader Abdallah, PMP
 
Oracle HCM and Taleo Enterprise Fusion-Taleo Integration Configuration Guide...
Oracle HCM  and Taleo Enterprise Fusion-Taleo Integration Configuration Guide...Oracle HCM  and Taleo Enterprise Fusion-Taleo Integration Configuration Guide...
Oracle HCM and Taleo Enterprise Fusion-Taleo Integration Configuration Guide...
Feras Ahmad
 
Oracle EBS R 12 Core hr user manual
Oracle EBS R 12 Core hr user manualOracle EBS R 12 Core hr user manual
Oracle EBS R 12 Core hr user manual
Feras Ahmad
 
Candy - Construction Estimating & Valuations - rev 2.01
Candy - Construction Estimating & Valuations - rev 2.01Candy - Construction Estimating & Valuations - rev 2.01
Candy - Construction Estimating & Valuations - rev 2.01
Jerico Awat
 
Windows Power Shell Sharepoint Better Together
 Windows Power Shell Sharepoint Better Together Windows Power Shell Sharepoint Better Together
Windows Power Shell Sharepoint Better Together
Baltimore SharePoint (BSPUG)
 
C201 candy estimating & valuations - rev 5
C201   candy estimating & valuations - rev 5C201   candy estimating & valuations - rev 5
C201 candy estimating & valuations - rev 5
Self-employed
 
C202 construction planning and programming
C202   construction planning and programmingC202   construction planning and programming
C202 construction planning and programming
ALEXANDRASUWANN
 
Admm crp oracle hr
Admm crp oracle hrAdmm crp oracle hr
Admm crp oracle hr
Feras Ahmad
 
Hsa programmers reference manual (version 1.0 provisional)
Hsa programmers reference manual (version 1.0 provisional)Hsa programmers reference manual (version 1.0 provisional)
Hsa programmers reference manual (version 1.0 provisional)
HSA Foundation
 
Erp
ErpErp
Biomechanics hfe
Biomechanics hfeBiomechanics hfe
Biomechanics hfe
Kassu Jilcha (PhD)
 

What's hot (15)

Android based crime manage system industrial project i
Android based crime manage system industrial project iAndroid based crime manage system industrial project i
Android based crime manage system industrial project i
 
Android based crime manage system industrial project i
Android based crime manage system industrial project iAndroid based crime manage system industrial project i
Android based crime manage system industrial project i
 
bi-foundation-suite-wp-215243
bi-foundation-suite-wp-215243bi-foundation-suite-wp-215243
bi-foundation-suite-wp-215243
 
Dassault Aviation - Company Profile
Dassault Aviation - Company ProfileDassault Aviation - Company Profile
Dassault Aviation - Company Profile
 
BR100 Oracle AP Setup
BR100 Oracle AP SetupBR100 Oracle AP Setup
BR100 Oracle AP Setup
 
Oracle HCM and Taleo Enterprise Fusion-Taleo Integration Configuration Guide...
Oracle HCM  and Taleo Enterprise Fusion-Taleo Integration Configuration Guide...Oracle HCM  and Taleo Enterprise Fusion-Taleo Integration Configuration Guide...
Oracle HCM and Taleo Enterprise Fusion-Taleo Integration Configuration Guide...
 
Oracle EBS R 12 Core hr user manual
Oracle EBS R 12 Core hr user manualOracle EBS R 12 Core hr user manual
Oracle EBS R 12 Core hr user manual
 
Candy - Construction Estimating & Valuations - rev 2.01
Candy - Construction Estimating & Valuations - rev 2.01Candy - Construction Estimating & Valuations - rev 2.01
Candy - Construction Estimating & Valuations - rev 2.01
 
Windows Power Shell Sharepoint Better Together
 Windows Power Shell Sharepoint Better Together Windows Power Shell Sharepoint Better Together
Windows Power Shell Sharepoint Better Together
 
C201 candy estimating & valuations - rev 5
C201   candy estimating & valuations - rev 5C201   candy estimating & valuations - rev 5
C201 candy estimating & valuations - rev 5
 
C202 construction planning and programming
C202   construction planning and programmingC202   construction planning and programming
C202 construction planning and programming
 
Admm crp oracle hr
Admm crp oracle hrAdmm crp oracle hr
Admm crp oracle hr
 
Hsa programmers reference manual (version 1.0 provisional)
Hsa programmers reference manual (version 1.0 provisional)Hsa programmers reference manual (version 1.0 provisional)
Hsa programmers reference manual (version 1.0 provisional)
 
Erp
ErpErp
Erp
 
Biomechanics hfe
Biomechanics hfeBiomechanics hfe
Biomechanics hfe
 

Viewers also liked

план конспект
план конспектплан конспект
план конспектGaliullina
 
Alexander timias
Alexander timiasAlexander timias
Alexander timias
Alex Ander
 
Tvg 2014 santa anita sweepstakes
Tvg 2014 santa anita sweepstakesTvg 2014 santa anita sweepstakes
Tvg 2014 santa anita sweepstakesTVG
 
Certificate Goal Setting
Certificate Goal SettingCertificate Goal Setting
Certificate Goal SettingSunita Gupta
 
Examentrimestral
ExamentrimestralExamentrimestral
Examentrimestral
kimberli luna
 
Nuevo documento de texto
Nuevo documento de textoNuevo documento de texto
Nuevo documento de texto
chiquixita
 
Zein da bizitzeko lekurik onena
Zein da bizitzeko lekurik onenaZein da bizitzeko lekurik onena
Zein da bizitzeko lekurik onena
E-idazkaritza
 

Viewers also liked (9)

план конспект
план конспектплан конспект
план конспект
 
Alexander timias
Alexander timiasAlexander timias
Alexander timias
 
Tvg 2014 santa anita sweepstakes
Tvg 2014 santa anita sweepstakesTvg 2014 santa anita sweepstakes
Tvg 2014 santa anita sweepstakes
 
Certificate Goal Setting
Certificate Goal SettingCertificate Goal Setting
Certificate Goal Setting
 
Examentrimestral
ExamentrimestralExamentrimestral
Examentrimestral
 
Nuevo documento de texto
Nuevo documento de textoNuevo documento de texto
Nuevo documento de texto
 
Zein da bizitzeko lekurik onena
Zein da bizitzeko lekurik onenaZein da bizitzeko lekurik onena
Zein da bizitzeko lekurik onena
 
HIV Eng poster
HIV Eng posterHIV Eng poster
HIV Eng poster
 
Single energy azizhu theory law 1
Single  energy  azizhu  theory  law  1Single  energy  azizhu  theory  law  1
Single energy azizhu theory law 1
 

Similar to IndieLabs-FormsApp Using Spring Framework

Developingsecurewebappswatchfire
DevelopingsecurewebappswatchfireDevelopingsecurewebappswatchfire
Developingsecurewebappswatchfire
Aung Khant
 
U M Lvs I D E F
U M Lvs I D E FU M Lvs I D E F
U M Lvs I D E F
Ngo Hung Long
 
Online Hotel Room Booking System
Online Hotel Room Booking SystemOnline Hotel Room Booking System
Online Hotel Room Booking System
Abhishek Kumar
 
Adf tutorial oracle
Adf tutorial oracleAdf tutorial oracle
Adf tutorial oracle
César Augusto Castillo Farfán
 
Hat app document
Hat app documentHat app document
Hat app document
Ashwin Ananthapadmanabhan
 
2011HW69968-Dissertation Final Report
2011HW69968-Dissertation Final Report2011HW69968-Dissertation Final Report
2011HW69968-Dissertation Final Report
Karthik Swaminathan V
 
Spring data-keyvalue-reference
Spring data-keyvalue-referenceSpring data-keyvalue-reference
Spring data-keyvalue-reference
dragos142000
 
Ipad Usability 2nd Edition
Ipad Usability 2nd EditionIpad Usability 2nd Edition
Ipad Usability 2nd Edition
jamiewaltz
 
App builder
App builderApp builder
App builder
bibis2
 
Life above the_service_tier_v1.1
Life above the_service_tier_v1.1Life above the_service_tier_v1.1
Life above the_service_tier_v1.1
Ganesh Prasad
 
WebIT2 Consultants Proposal
WebIT2 Consultants ProposalWebIT2 Consultants Proposal
WebIT2 Consultants Proposal
Sarah Killey
 
Oracl apps api usages
Oracl apps api usagesOracl apps api usages
Oracl apps api usages
rakhe_r
 
Book of-vaadin
Book of-vaadinBook of-vaadin
Book of-vaadin
VLASLOV
 
Firstcup
FirstcupFirstcup
Firstcup
PrinceGuru MS
 
Open acc.1.0
Open acc.1.0Open acc.1.0
Open acc.1.0
shengmingzhiyu
 
RESTful Day 7
RESTful Day 7RESTful Day 7
RESTful Day 7
Akhil Mittal
 
Zend framework 1.10.x English
Zend framework 1.10.x EnglishZend framework 1.10.x English
Zend framework 1.10.x English
Mostafa Mahmoud
 
Lean Six Sigma Manual
Lean Six Sigma ManualLean Six Sigma Manual
Lean Six Sigma Manual
Association of Colleges
 
Final Year Project (ISP),Project Demo
Final Year Project (ISP),Project DemoFinal Year Project (ISP),Project Demo
Final Year Project (ISP),Project Demo
Abdul Aslam
 
FY2013 USAF Rapid Innovation Fund BAA Announcement
FY2013 USAF Rapid Innovation Fund BAA AnnouncementFY2013 USAF Rapid Innovation Fund BAA Announcement
FY2013 USAF Rapid Innovation Fund BAA Announcement
Tom "Blad" Lindblad
 

Similar to IndieLabs-FormsApp Using Spring Framework (20)

Developingsecurewebappswatchfire
DevelopingsecurewebappswatchfireDevelopingsecurewebappswatchfire
Developingsecurewebappswatchfire
 
U M Lvs I D E F
U M Lvs I D E FU M Lvs I D E F
U M Lvs I D E F
 
Online Hotel Room Booking System
Online Hotel Room Booking SystemOnline Hotel Room Booking System
Online Hotel Room Booking System
 
Adf tutorial oracle
Adf tutorial oracleAdf tutorial oracle
Adf tutorial oracle
 
Hat app document
Hat app documentHat app document
Hat app document
 
2011HW69968-Dissertation Final Report
2011HW69968-Dissertation Final Report2011HW69968-Dissertation Final Report
2011HW69968-Dissertation Final Report
 
Spring data-keyvalue-reference
Spring data-keyvalue-referenceSpring data-keyvalue-reference
Spring data-keyvalue-reference
 
Ipad Usability 2nd Edition
Ipad Usability 2nd EditionIpad Usability 2nd Edition
Ipad Usability 2nd Edition
 
App builder
App builderApp builder
App builder
 
Life above the_service_tier_v1.1
Life above the_service_tier_v1.1Life above the_service_tier_v1.1
Life above the_service_tier_v1.1
 
WebIT2 Consultants Proposal
WebIT2 Consultants ProposalWebIT2 Consultants Proposal
WebIT2 Consultants Proposal
 
Oracl apps api usages
Oracl apps api usagesOracl apps api usages
Oracl apps api usages
 
Book of-vaadin
Book of-vaadinBook of-vaadin
Book of-vaadin
 
Firstcup
FirstcupFirstcup
Firstcup
 
Open acc.1.0
Open acc.1.0Open acc.1.0
Open acc.1.0
 
RESTful Day 7
RESTful Day 7RESTful Day 7
RESTful Day 7
 
Zend framework 1.10.x English
Zend framework 1.10.x EnglishZend framework 1.10.x English
Zend framework 1.10.x English
 
Lean Six Sigma Manual
Lean Six Sigma ManualLean Six Sigma Manual
Lean Six Sigma Manual
 
Final Year Project (ISP),Project Demo
Final Year Project (ISP),Project DemoFinal Year Project (ISP),Project Demo
Final Year Project (ISP),Project Demo
 
FY2013 USAF Rapid Innovation Fund BAA Announcement
FY2013 USAF Rapid Innovation Fund BAA AnnouncementFY2013 USAF Rapid Innovation Fund BAA Announcement
FY2013 USAF Rapid Innovation Fund BAA Announcement
 

IndieLabs-FormsApp Using Spring Framework

  • 1. IndieLabs Forms App Using Spring Framework Spring Framework MVC Development Abdulah Al Bahhar 7/21/2015
  • 2. Table of Contents 1. Introduction ........................................................................................................................... 1 1.1. Application Overview .................................................................................................... 1 1.2. Outcomes........................................................................................................................ 1 1.3. Pre-requisites.................................................................................................................. 1 1.4. Requirements.................................................................................................................. 1 1.5. GitHub Repository ......................................................................................................... 1 2. STS Setup.............................................................................................................................. 2 2.1. STS Loading Main Class Bug........................................................................................ 2 2.2. POM.xml Dependencies................................................................................................. 3 2.2.1. JPA Dependencies................................................................................................... 3 2.2.2 Spring Security Dependencies.................................................................................. 3 2.2.3 Hashing Utilities Dependencies................................................................................ 4 2.2.4 AOP Dependency..................................................................................................... 4 2.2.5 Testing Dependencies............................................................................................... 4 2.2.6 MySQL Dependency................................................................................................ 4 2.3. Servlet-Context.xml Configuration................................................................................ 5 2.4. Datasource.xml Configuration ....................................................................................... 7 2.5. Spring-Security.xml Configuration ................................................................................ 8 2.6. Web.xml Configuration................................................................................................ 11 2.7. Packages....................................................................................................................... 13 2.8. Static Resources ........................................................................................................... 13 2.9. Class Diagram .............................................................................................................. 13 2.10. Database Schema........................................................................................................ 14 3. Models................................................................................................................................. 20 3.1. User .............................................................................................................................. 20 3.2. Role .............................................................................................................................. 24 3.3. Form ............................................................................................................................. 25 3.4. Question........................................................................................................................ 26 3.5. SimpleQuestion ............................................................................................................ 27 3.6. MCQuestion ................................................................................................................. 28 3.7. Choice........................................................................................................................... 29 3.8. SimpleAnswer .............................................................................................................. 30 3.9. ChoiceAnswer .............................................................................................................. 31 4. Repositories......................................................................................................................... 33 4.1. UserRepository............................................................................................................. 33
  • 3. 4.2. RoleRepository............................................................................................................. 33 4.3. FormRepository............................................................................................................ 33 4.4. QuestionRepository...................................................................................................... 34 4.5. SimpleQuestionRepository........................................................................................... 34 4.6. MCQuestionRepository................................................................................................ 34 4.7. ChoiceRepository......................................................................................................... 34 4.8. SimpleAnswerRepository............................................................................................. 35 4.9. ChoiceAnswerRepository............................................................................................. 35 5. Services ............................................................................................................................... 35 5.1. CustomUserDetailsService........................................................................................... 35 5.2. UserService .................................................................................................................. 38 5.3. RoleService .................................................................................................................. 39 5.4. FormService ................................................................................................................. 40 5.5. SimpleQuestionService ................................................................................................ 40 5.6. MCQuestionService ..................................................................................................... 41 5.7. ChoiceService............................................................................................................... 42 5.8. SimpleAnswerService .................................................................................................. 42 5.9. ChoiceAnswerService .................................................................................................. 43 6. MCQuestion Wrapper Class................................................................................................ 44 7. Controllers........................................................................................................................... 45 7.1. Home Controller........................................................................................................... 45 7.2. SecurityNavigation Controller...................................................................................... 46 7.3. FormsController ........................................................................................................... 47 7.4. SimpleQuestionsController .......................................................................................... 49 7.5. MCQuestionsController ............................................................................................... 51 7.6. SimpleAnswerController.............................................................................................. 54 7.7. ChoiceAnswerController.............................................................................................. 55 8. Views................................................................................................................................... 57 8.1. login-form.jsp............................................................................................................... 57 8.2. Users............................................................................................................................. 58 8.2.1. Register.jsp............................................................................................................ 58 8.3. Forms............................................................................................................................ 59 8.3.1. index.jsp ................................................................................................................ 59 8.3.2. details.jsp............................................................................................................... 61 8.3.3. create.jsp................................................................................................................ 63 8.3.4. edit.jsp ................................................................................................................... 64
  • 4. 8.4. SimpleQuestions........................................................................................................... 65 8.4.1. details.jsp............................................................................................................... 65 8.4.2. create.jsp................................................................................................................ 67 8.4.3. edit.jsp ................................................................................................................... 67 8.5. MCQuestions................................................................................................................ 68 8.5.1. details.jsp............................................................................................................... 68 8.5.2. create.jsp................................................................................................................ 70 8.5.3. edit.jsp ................................................................................................................... 71 9. Sample Screenshots............................................................................................................. 72 10. Useful Resources............................................................................................................... 74
  • 5. 1 | P a g e 1. Introduction 1.1. Application Overview This tutorial will take you through learning how to develop a kind of simple Java EE web application using Spring MVC. The idea of the application is very simple, we have a collection of forms that contain two types of questions, written and multiple choice. The admin can manage all of these, and the regular users can answer those questions many times. 1.2. Outcomes At the end of this tutorial, you should be able to achieve the following:  Setup the development environment.  Setup the XML configurations for dependencies, data source and Spring Security.  Create models with the proper relationships mapped to the database.  Create services.  Create repositories.  Create controllers.  Create views. 1.3. Pre-requisites 1. Good knowledge of development using Java SE. 2. Basic knowledge of MVC pattern. 3. Basic knowledge of HTML. 1.4. Requirements To follow along with the tutorial, you should have the following: 1. STS IDE installed. (In this tutorial, version 3.6.4 is used) 2. JDK 1.6 or 1.7. (version 1.8 results in problems in the version of STS used, not sure about higher versions of STS) 3. MySQL 5 database. (In this tutorial, Wamp server is used for this purpose) 1.5. GitHub Repository All the final files of the project exist on the GitHub repository on the following link: https://github.com/abahhar/FormsApp
  • 6. 2 | P a g e 2. STS Setup First, we have to create a new Spring MVC project, you could create a new one and it will create all the default files and directory structure we need. To create a new Spring MVC Project, please do the following: 1. FileNewSpring Project. 2. Set the project name to FormsApp. 3. Choose Spring MVC Project. 4. Write the package name as: com.abahhar.formsApp. 5. Click finish. The default Spring MVC project which is created contains a default HomeController in the package “com.abahhar.formsapp” and a home.jsp webpage in the views folder. This simple application shows you a hello world page with the current date and time. To run the application, you could simply drag the application folder “FormsApp” to the Pivotal tc server which exists in the window below the package explorer, and then in the same window of the servers, you simply click the green arrow to run the application. 2.1. STS Loading Main Class Bug In the current version and the following one, there’s a bug in the IDE that results in not running the application, you might encounter a statement in the output window that says “Could not find or load main class”. To solve the issue, please follow the first solution suggested in the following URL: http://stackoverflow.com/questions/29004274/error-after-update-to-sts-3-6-4-release
  • 7. 3 | P a g e 2.2. POM.xml Dependencies To be able to use libraries in Spring Framework, we should handle the dependencies ourselves in pom.xml file which exists in the root document of our application. This section provides you with the needed dependencies to be added. 2.2.1. JPA Dependencies 4. <!-- JPA Dependencies --> 5. <dependency> 6. <groupId>org.springframework</groupId> 7. <artifactId>spring-core</artifactId> 8. <version>${org.springframework-version}</version> 9. </dependency> 10. <dependency> 11. <groupId>org.springframework.data</groupId> 12. <artifactId>spring-data-jpa</artifactId> 13. <version>1.2.0.RELEASE</version> 14. </dependency> 15. <dependency> 16. <groupId>org.springframework</groupId> 17. <artifactId>spring-orm</artifactId> 18. <version>${org.springframework- version}</version> 19. </dependency> 20. <dependency> 21. <groupId>org.hibernate</groupId> 22. <artifactId>hibernate- entitymanager</artifactId> 23. <version>4.1.7.Final</version> 24. </dependency> 2.2.2 Spring Security Dependencies <!-- Spring Security --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-core</artifactId> <version>3.1.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>3.1.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>3.1.3.RELEASE</version> </dependency> <!-- Spring Security tag library to be used in the views --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-taglibs</artifactId> <version>3.1.3.RELEASE</version> </dependency>
  • 8. 4 | P a g e 2.2.3 Hashing Utilities Dependencies <!-- Hashing utilities dependencies --> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.10</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.6.6</version> </dependency> 2.2.4 AOP Dependency <!-- AOP dependency --> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>2.2</version> </dependency> 2.2.5 Testing Dependencies <!-- Testing Dependencies --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.5</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${org.springframework-version}</version> <scope>test</scope> </dependency> 2.2.6 MySQL Dependency <!-- MYSQL --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency>
  • 9. 5 | P a g e 2.3. Servlet-Context.xml Configuration This configuration file exist in the following directory: FormsAppsrcmainwebappWEB-INFspringappServlet Please make sure that it contains the following code: <?xml version="1.0" encoding="UTF-8" standalone="no"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd" xmlns:security="http://www.springframework.org/schema/security"> <!-- Enables the Spring MVC @Controller programming model --> <mvc:annotation-driven /> <!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory --> <mvc:resources mapping="/resources/**" location="/resources/" /> <!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResol ver"> <property name="prefix" value="/WEB-INF/views/" /> <property name="suffix" value=".jsp" /> </bean> <context:annotation-config/> <context:component-scan base-package="com.abahhar.formsapp" /> <jpa:repositories base-package="com.abahhar.formsapp.repository"/> <tx:annotation-driven/> </beans>
  • 10. 6 | P a g e Please notice this fragment of code: <context:annotation-config/> <context:component-scan base-package="com.abahhar.formsapp" /> <jpa:repositories base-package="com.abahhar.formsapp.repository"/> <tx:annotation-driven/> What this fragment does is that it scans for the Spring components and repositories in the specified packages. Components can be controllers or services. This scan is done automatically by Spring Framework in order to inject the components and repositories later in the code, this is the dependency injection feature supported in Spring Framework, later in the code when we want to inject a service or repository, we will need to annotate it with @Autowired, and Spring Framework will do the job of injecting the right dependency since it scans in the proper packages we specified in this configuration. Furthermore, notice the prefix and the suffix values specified by the default Spring MVC Project, these values will be used to enable the ViewResolver to find the view that we want. For example, in the controller we could return a string of a view as “/forms/create”, this string will be evaluated as “WEB-INF/views/forms/create.jsp”. As you notice, the prefix is added to the beginning of the returned string and the suffix is added to the end of it.
  • 11. 7 | P a g e 2.4. Datasource.xml Configuration Here we setup the configuration for the database connection, please be sure to include the configuration file datasource.xml in the package “src/main/resources”, and include the following fragment of code: <?xml version="1.0" encoding="UTF-8" standalone="no"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost/helloWorld"/> <property name="username" value="root"/> <property name="password" value=""/> </bean> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactory Bean"> <property name="dataSource" ref="dataSource" /> <property name="packagesToScan" value="com.abahhar.formsapp.domain" /> <property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence" /> <property name="loadTimeWeaver"> <bean class="org.springframework.instrument.classloading.InstrumentationLoa dTimeWeaver" /> </property> <property name="jpaProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop> <prop key="hibernate.max_fetch_depth">3</prop> <prop key="hibernate.jdbc.fetch_size">50</prop> <prop key="hibernate.jdbc.batch_size">10</prop> <prop key="hibernate.show_sql">true</prop> </props> </property> </bean> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> </beans> For your settings, put the correct link for the local server hosting the database and its port if not 80, and the name of the database after the slash “/”, and the correct username and password. In this tutorial, the name of the database is helloWorld.
  • 12. 8 | P a g e 2.5. Spring-Security.xml Configuration Here we setup the configuration for Spring Security. Spring Security is a ready library that is used for authentication and authorization of users. Using the following library, we can have a login system and every user could have roles which with he can be authorized to the different parts of the application. Please be sure to include the configuration file spring-security.xml in the package “src/main/resources”, and include the following fragment of code: <?xml version="1.0" encoding="UTF-8" standalone="no"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security- 3.1.xsd" xmlns:security="http://www.springframework.org/schema/security"> <context:annotation-config /> <context:component-scan base-package="com.abahhar.formsapp.service" /> <jpa:repositories base-package="com.abahhar.formsapp.repository"/> <!-- Spring Security Configuration --> <security:http pattern="/resources/**" security="none"/> <!-- Permit access to static resources --> <security:http auto-config='true' use-expressions="true"> <!-- use- expressions enables using expressions like isAuthorized(), isAnonymous() & isRole() --> <security:intercept-url pattern="/user-login" access="isAnonymous()"/> <!-- To avoid redirect loop since login-page changed --> <security:intercept-url pattern="/forms/**" access="hasRole('ROLE_USER')"/> <security:intercept-url pattern="/simpleQuestions/**" access="hasRole('ROLE_USER')"/> <security:intercept-url pattern="/mcQuestions/**" access="hasRole('ROLE_USER')"/> <security:intercept-url pattern="/simpleAnswers/**" access="hasRole('ROLE_USER')"/>
  • 13. 9 | P a g e <security:intercept-url pattern="/choiceAnswers/**" access="hasRole('ROLE_USER')"/> <security:form-login login-page="/user-login" default-target-url="/forms" always-use-default-target="true" authentication-failure-url="/error-login" /> <security:logout logout-success-url="/forms" /> </security:http> <!-- <security:authentication-manager> <security:authentication-provider> <security:user-service> <security:user name="jimi" password="jimispassword" authorities="ROLE_USER, ROLE_ADMIN" /> <security:user name="bob" password="bobspassword" authorities="ROLE_USER" /> </security:user-service> </security:authentication-provider> </security:authentication-manager> --> <security:authentication-manager> <security:authentication-provider user-service- ref="customUserDetailsService"> <security:password-encoder hash="sha" /> </security:authentication-provider> </security:authentication-manager> </beans> It seems that this file contains a lot of things, but let’s decompose it and explain what’s happening. <context:annotation-config /> <context:component-scan base-package="com.abahhar.formsapp.service" /> <jpa:repositories base-package="com.abahhar.formsapp.repository"/> We have seen this fragment of code in servlet-context.xml, but because of the decomposition we are making, the Spring Security later will need to inject some service dependencies for its library, and that won’t work unless we add the following fragment of code in this file.
  • 14. 10 | P a g e <!-- Spring Security Configuration --> <security:http pattern="/resources/**" security="none"/> <!-- Permit access to static resources --> <security:http auto-config='true' use-expressions="true"> <!-- use- expressions enables using expressions like isAuthorized(), isAnonymous() & isRole() --> <security:intercept-url pattern="/user-login" access="isAnonymous()"/> <!-- To avoid redirect loop since login-page changed --> <security:intercept-url pattern="/forms/**" access="hasRole('ROLE_USER')"/> <security:intercept-url pattern="/simpleQuestions/**" access="hasRole('ROLE_USER')"/> <security:intercept-url pattern="/mcQuestions/**" access="hasRole('ROLE_USER')"/> <security:intercept-url pattern="/simpleAnswers/**" access="hasRole('ROLE_USER')"/> <security:intercept-url pattern="/choiceAnswers/**" access="hasRole('ROLE_USER')"/> <security:form-login login-page="/user-login" default-target-url="/forms" always-use-default-target="true" authentication-failure-url="/error-login" /> <security:logout logout-success-url="/forms" /> </security:http> Here we setup the authorization settings, meaning that which links are to be accessed and which are denied for each role. First we set the resources folder to be accessible by all, because there is where the images, CSS and JavaScript files reside. Second, we set to attributes in the second http tag, auto-config to true, and use- expressions to true. Auto-config will make the Spring Security insert default tags and attributes for setting everything, because there are other things that we do not want to bother ourselves with, so we let it set it to default values. Use-expression attribute will enable us to use expressions like “isAnonymous()” and “hasRole()” in the configuration file and the views later, to be able show the proper features to proper users. Intercept-url tag is used to set two things, the URL pattern and the role that is authorized to access that URL pattern. You can set whatever URL to whatever role you would like, taking into account that in this application we will have ROLE_ADMIN and ROLE_USER. Form-login tag sets the default URL for the login page, the default target URL which to be directed to after login, the page to be directed to if the login fails and the page to be directed to after the logout action.
  • 15. 11 | P a g e The last fragments to discuss are the authentication-manager tag, the commented one could be used to have in-memory users set up by you as you like, which you could use in running the application as they were to exist as registered users. The second and used one, is setup to use the customized user service which we will setup later, and have the hashing setup to be using sha encryption, you could use other hashing settings such as “plaintext”, which deals with the password with no encryption, and “md5”, which uses md5 encryption. 2.6. Web.xml Configuration The last configuration file to modify is web.xml, which exists in the following directory: FormsAppsrcmainwebappWEB-INF Please make sure that the file contains the following fragment of code: <?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <!-- The definition of the Root Spring Container shared by all Servlets and Filters --> <context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/spring/root-context.xml, classpath:datasource.xml, classpath:spring-security.xml </param-value> </context-param> <!-- Creates the Spring Container shared by all Servlets and Filters --> <listener> <listener- class>org.springframework.web.context.ContextLoaderListener</listener -class> </listener> <!-- Processes application requests --> <servlet> <servlet-name>appServlet</servlet-name> <servlet- class>org.springframework.web.servlet.DispatcherServlet</servlet- class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/appServlet/servlet- context.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping>
  • 16. 12 | P a g e <servlet-name>appServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!-- Spring Security Filters --> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter- class>org.springframework.web.filter.DelegatingFilterProxy</filter- class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app> Here we have to things added to the default file, the import of the datasource.xml and spring-security.xml files in this fragment of code: <context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/spring/root-context.xml, classpath:datasource.xml, classpath:spring-security.xml </param-value> </context-param> And some settings for springSecurityFilterChain that must exist, so that Spring Security to works: <!-- Spring Security Filters --> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter- class>org.springframework.web.filter.DelegatingFilterProxy</filter- class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> Please note in the first fragment of code, “classpath” evaluates to the directory “src/main/resources”, which is the package stated that you should include the files in when explaining setting the configuration files.
  • 17. 13 | P a g e 2.7. Packages In this tutorial, we setup the project to have the following packages: 1. Com.abahhar.formsapp 2. Com.abahhar.formsapp.controller 3. Com.abahhar.formsapp.domain 4. Com.abahhar.formsapp.repository 5. Com.abahhar.formsapp.service 6. Com.abahhar.formsapp.wrapper 2.8. Static Resources Static resources such as images, CSS and JavaScript files should exist in the following directory: “FormsAppsrcmainwebappresources”. 2.9. Class Diagram This is the class diagram that the web application is based on:
  • 18. 14 | P a g e 2.10. Database Schema The following is the schema of the database tables that we will be using: Roles Role ID Role Users User ID Username Password UsersRoles User ID Role ID Forms Form ID Title AnsweredForms User ID Form ID Questions Question ID Text Form ID
  • 19. 15 | P a g e SimpleQuestions Question ID NumberOfQuestions MCQuestions Question ID Choices Choice ID Text Question ID AnsweredSimpleQuestion SimpleAnswer ID Text Question ID User ID AnsweredMCQuestion MCAnswer ID Choice ID Question ID User ID
  • 20. 16 | P a g e In order to create the database tables in your database, please use the following SQL statements: -- -- Table structure for table `choiceanswers` -- CREATE TABLE `choiceanswers` ( `id` int(11) NOT NULL AUTO_INCREMENT, `choice_id` int(11) NOT NULL, `question_id` int(11) NOT NULL, `user_id` int(11) NOT NULL, PRIMARY KEY (`id`), KEY `choice_id` (`choice_id`), KEY `question_id` (`question_id`), KEY `user_id` (`user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=13 ; -- -------------------------------------------------------- -- -- Table structure for table `choices` -- CREATE TABLE `choices` ( `id` int(11) NOT NULL AUTO_INCREMENT, `text` varchar(50) NOT NULL, `question_id` int(11) NOT NULL, PRIMARY KEY (`id`), KEY `question_id` (`question_id`), KEY `question_id_2` (`question_id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=78 ; -- -------------------------------------------------------- -- -- Table structure for table `forms` -- CREATE TABLE `forms` ( `id` int(11) NOT NULL AUTO_INCREMENT, `title` varchar(50) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=8 ; -- -------------------------------------------------------- -- -- Table structure for table `mcquestions` -- CREATE TABLE `mcquestions` ( `id` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=47 ; -- -------------------------------------------------------- -- -- Table structure for table `questions`
  • 21. 17 | P a g e -- CREATE TABLE `questions` ( `id` int(11) NOT NULL AUTO_INCREMENT, `text` varchar(50) NOT NULL, `form_id` int(11) NOT NULL, PRIMARY KEY (`id`), KEY `form_id` (`form_id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=47 ; -- -------------------------------------------------------- -- -- Table structure for table `roles` -- CREATE TABLE `roles` ( `id` int(6) NOT NULL AUTO_INCREMENT, `role` varchar(20) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ; -- -------------------------------------------------------- -- -- Table structure for table `simpleanswers` -- CREATE TABLE `simpleanswers` ( `id` int(11) NOT NULL AUTO_INCREMENT, `text` varchar(50) NOT NULL, `question_id` int(11) NOT NULL, `user_id` int(11) NOT NULL, PRIMARY KEY (`id`), KEY `question_id` (`question_id`), KEY `user_id` (`user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=9 ; -- -------------------------------------------------------- -- -- Table structure for table `simplequestions` -- CREATE TABLE `simplequestions` ( `id` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=30 ; -- -------------------------------------------------------- -- -- Table structure for table `users` -- CREATE TABLE `users` ( `id` int(6) NOT NULL AUTO_INCREMENT, `login` varchar(20) NOT NULL, `password` varchar(50) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=16 ;
  • 22. 18 | P a g e -- -------------------------------------------------------- -- -- Table structure for table `usersforms` -- CREATE TABLE `usersforms` ( `user_id` int(11) NOT NULL, `form_id` int(11) NOT NULL, PRIMARY KEY (`user_id`,`form_id`), KEY `form_id` (`form_id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; -- -------------------------------------------------------- -- -- Table structure for table `user_roles` -- CREATE TABLE `user_roles` ( `user_id` int(6) NOT NULL, `role_id` int(6) NOT NULL, KEY `user` (`user_id`), KEY `role` (`role_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- -- Constraints for dumped tables -- -- -- Constraints for table `choiceanswers` -- ALTER TABLE `choiceanswers` ADD CONSTRAINT `choiceanswers_ibfk_1` FOREIGN KEY (`choice_id`) REFERENCES `choices` (`id`) ON DELETE CASCADE, ADD CONSTRAINT `choiceanswers_ibfk_2` FOREIGN KEY (`question_id`) REFERENCES `mcquestions` (`id`) ON DELETE CASCADE, ADD CONSTRAINT `choiceanswers_ibfk_3` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE; -- -- Constraints for table `choices` -- ALTER TABLE `choices` ADD CONSTRAINT `choices_ibfk_1` FOREIGN KEY (`question_id`) REFERENCES `mcquestions` (`id`) ON DELETE CASCADE; -- -- Constraints for table `mcquestions` -- ALTER TABLE `mcquestions` ADD CONSTRAINT `mcquestions_ibfk_1` FOREIGN KEY (`id`) REFERENCES `questions` (`id`) ON DELETE CASCADE; -- -- Constraints for table `questions` -- ALTER TABLE `questions`
  • 23. 19 | P a g e ADD CONSTRAINT `questions_ibfk_1` FOREIGN KEY (`form_id`) REFERENCES `forms` (`id`) ON DELETE CASCADE; -- -- Constraints for table `simpleanswers` -- ALTER TABLE `simpleanswers` ADD CONSTRAINT `simpleanswers_ibfk_1` FOREIGN KEY (`question_id`) REFERENCES `simplequestions` (`id`) ON DELETE CASCADE, ADD CONSTRAINT `simpleanswers_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE; -- -- Constraints for table `simplequestions` -- ALTER TABLE `simplequestions` ADD CONSTRAINT `simplequestions_ibfk_1` FOREIGN KEY (`id`) REFERENCES `questions` (`id`) ON DELETE CASCADE; -- -- Constraints for table `usersforms` -- ALTER TABLE `usersforms` ADD CONSTRAINT `usersforms_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE, ADD CONSTRAINT `usersforms_ibfk_2` FOREIGN KEY (`form_id`) REFERENCES `forms` (`id`) ON DELETE CASCADE; Also, use the following SQL statements to populate users, roles and user_roles tables: INSERT INTO `users` (`id`, `login`, `password`) VALUES (1, 'admin', '3d4f2bf07dc1be38b20cd6e46949a1071f9d0e3d'), (2, 'user', '273a0c7bd3c679ba9a6f5d99078e36e85d02b952'); INSERT INTO `roles` (`id`, `role`) VALUES (1, 'admin'), (2, 'user'); INSERT INTO `user_roles` (`user_id`, `role_id`) VALUES (1, 1), (2, 2); The password for admin is: 111111 The password for user is: 222222
  • 24. 20 | P a g e 3. Models According to the class diagram, the application will have the following models:  User  Role  Form  Simple Question  MC Question  Choice  Answered Simple Question  Answered MC Question In this section, the code of the models and some explanation of the data annotations used are to be provided. Please make sure that all the models are to be included in the package “com.abahhar.formsapp.domain”. 3.1. User package com.abahhar.formsapp.domain; import java.util.Set; import javax.persistence.*; @Entity @Table(name="users") public class User { @Id @GeneratedValue private Integer id; private String login; private String password; //---------------------------------Navigation properties--------- ------------------------// @OneToOne(cascade=CascadeType.ALL) @JoinTable(name="user_roles", joinColumns = {@JoinColumn(name="user_id", referencedColumnName="id")}, inverseJoinColumns = {@JoinColumn(name="role_id", referencedColumnName="id")} ) private Role role; @OneToMany(mappedBy="user", cascade=CascadeType.REMOVE, fetch=FetchType.EAGER) private Set<SimpleAnswer> simpleAnswers; @OneToMany(mappedBy="user", cascade=CascadeType.REMOVE, fetch=FetchType.EAGER) private Set<ChoiceAnswer> choiceAnswers;
  • 25. 21 | P a g e public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getLogin() { return login; } public void setLogin(String login) { this.login = login; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Role getRole() { return role; } public void setRole(Role role) { this.role = role; } public Set<SimpleAnswer> getSimpleAnswers() { return simpleAnswers; } public void setSimpleAnswers(Set<SimpleAnswer> simpleAnswers) { this.simpleAnswers = simpleAnswers; } public Set<ChoiceAnswer> getChoiceAnswers() { return choiceAnswers; } public void setChoiceAnswers(Set<ChoiceAnswer> choiceAnswers) { this.choiceAnswers = choiceAnswers; } }
  • 26. 22 | P a g e This is a regular Java class that you would create, the only thing that you might be concerned about are the data annotations used, and here is an explanation for each: Data Annotation Description Entity Used to declare a class as an entity to be used in data access Table Used to specify the name of the table that the model is going to be mapped to Id Used to specify that an attribute is the primary key GeneratedValue Used to specify that an attribute is automatically generated “Auto_Increment” OneToOne Used to specify that a property will have a one to one relationship with another navigation property. Cascade attribute is used to specify the type of cascade JoinTable Used to specify the name of the table that will be used to join two tables, in this model, the table “user_roles” is used to join the “user” and “role” tables JoinColumns Used to specify to map the joined column with the models properties, in this example, “user_id” is mapped to the id of this current class, and “role_id” is mapped to the id of the Role class, since the annotations are put above the navigation property “role”
  • 27. 23 | P a g e OneToMany Used to specify that the current class is having a one-to-many relationship with another navigation property, the user has many simple answers and many choice answers. MappedBy property specifies which navigation property in the other end is used for this class, for example, mappedBy=user, means that simpleAnswers and choiceAnswers will have a navigation property called user, which will be used for this relationship. Cascade specifies the type of cascade. Fetch specifies if the fetching is lazy or eager.
  • 28. 24 | P a g e 3.2. Role package com.abahhar.formsapp.domain; import java.util.Set; import javax.persistence.*; @Entity @Table(name="roles") public class Role { @Id @GeneratedValue private Integer id; private String role; //---------------------------------Navigation properties--------- ------------------------// @OneToMany(cascade=CascadeType.ALL) @JoinTable(name="user_roles", joinColumns = {@JoinColumn(name="role_id", referencedColumnName="id")}, inverseJoinColumns = {@JoinColumn(name="user_id", referencedColumnName="id")} ) private Set<User> userRoles; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getRole() { return role; } public void setRole(String role) { this.role = role; } public Set<User> getUserRoles() { return userRoles; } public void setUserRoles(Set<User> userRoles) { this.userRoles = userRoles; } }
  • 29. 25 | P a g e 3.3. Form package com.abahhar.formsapp.domain; import java.util.Set; import javax.persistence.*; @Entity @Table(name="forms") public class Form { @Id @GeneratedValue private Integer id; @Column private String title; public Form(){ } public Form(String title){ this.title = title; } //---------------------------------Navigation properties------- --------------------------// @OneToMany(mappedBy="form", cascade=CascadeType.REMOVE, fetch=FetchType.EAGER) private Set<Question> questions; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public Set<Question> getQuestions() { return questions; } public void setQuestions(Set<Question> questions) { this.questions = questions; } }
  • 30. 26 | P a g e 3.4. Question package com.abahhar.formsapp.domain; import javax.persistence.*; @Entity @Table(name="questions") @Inheritance(strategy=InheritanceType.JOINED) //Joined strategy for table per subclass public class Question { @Id @GeneratedValue private Integer id; @Column private String text; public Question(){ } public Question(String text){ this.text = text; } //---------------------------------Navigation properties------- --------------------------// @ManyToOne @JoinColumn(name="form_id") private Form form; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getText() { return text; } public void setText(String text) { this.text = text; } public Form getForm() { return form; } public void setForm(Form form) { this.form = form; } }
  • 31. 27 | P a g e Since we are using inheritance and we want it to be mapped to the database schema, @Inheritance data annotation is used to specify the strategy to be used. According to the database schema, we are using the joined strategy. To read more about this strategy and other strategies with applied examples, please refer to the following article: http://www.dineshonjava.com/p/implementing-inheritance-in- hibernate.html#.VZuKlRuqqko Also, @ManyToOne annotation is used for the relationship used between the form and question. Since Form class contains @OneToMany, meaning one form to many questions, then in the other side, which is Question class, we annotate the form navigation property with @ManyToOne, meaning many questions to one form. @JoinColumn is used to specify the foreign key to be mapped to in the Questions table, which in this case is form_id, to be used to refer to the form. 3.5. SimpleQuestion package com.abahhar.formsapp.domain; import java.util.Set; import javax.persistence.*; @Entity @Table(name="simplequestions") public class SimpleQuestion extends Question { public SimpleQuestion(){ super(); } public SimpleQuestion(String text){ super(text); } //---------------------------------Navigation properties------- --------------------------// @OneToMany(mappedBy="simpleQuestion", cascade=CascadeType.REMOVE, fetch=FetchType.EAGER) private Set<SimpleAnswer> simpleAnswers; public Set<SimpleAnswer> getSimpleAnswers() { return simpleAnswers; } public void setSimpleAnswers(Set<SimpleAnswer> simpleAnswers) { this.simpleAnswers = simpleAnswers; } }
  • 32. 28 | P a g e 3.6. MCQuestion package com.abahhar.formsapp.domain; import java.util.Iterator; import java.util.Set; import javax.persistence.*; @Entity @Table(name="mcquestions") public class MCQuestion extends Question { public MCQuestion(){ super(); } //---------------------------------Navigation properties------- --------------------------// @OneToMany(mappedBy="mcQuestion", cascade=CascadeType.REMOVE, fetch=FetchType.EAGER) private Set<Choice> choices; @OneToMany(mappedBy="mcQuestion", cascade=CascadeType.REMOVE, fetch=FetchType.EAGER) private Set<ChoiceAnswer> choiceAnswers; public Set<Choice> getChoices() { return choices; } public void setChoices(Set<Choice> choices) { this.choices = choices; } public Set<ChoiceAnswer> getChoiceAnswers() { return choiceAnswers; } public void setChoiceAnswers(Set<ChoiceAnswer> choiceAnswers) { this.choiceAnswers = choiceAnswers; } }
  • 33. 29 | P a g e 3.7. Choice package com.abahhar.formsapp.domain; import java.util.Set; import javax.persistence.*; @Entity @Table(name="choices") public class Choice { @Id @GeneratedValue private Integer id; @Column private String text; public Choice(){ } public Choice(String text){ this.text = text; } //---------------------------------Navigation properties------- --------------------------// @ManyToOne @JoinColumn(name="question_id") private MCQuestion mcQuestion; @OneToMany(mappedBy="choice", cascade=CascadeType.REMOVE, fetch=FetchType.EAGER) private Set<ChoiceAnswer> choiceAnswers; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getText() { return text; } public void setText(String text) { this.text = text; } public MCQuestion getMcQuestion() { return mcQuestion; } public void setMcQuestion(MCQuestion mcQuestion) { this.mcQuestion = mcQuestion; }
  • 34. 30 | P a g e public Set<ChoiceAnswer> getChoiceAnswers() { return choiceAnswers; } public void setChoiceAnswers(Set<ChoiceAnswer> choiceAnswers) { this.choiceAnswers = choiceAnswers; } } 3.8. SimpleAnswer package com.abahhar.formsapp.domain; import javax.persistence.*; @Entity @Table(name="simpleanswers") public class SimpleAnswer { @Id @GeneratedValue private Integer id; @Column private String text; public SimpleAnswer(){ } public SimpleAnswer(String text){ this.text = text; } //---------------------------------Navigation properties------- --------------------------// @ManyToOne @JoinColumn(name="question_id") private SimpleQuestion simpleQuestion; @ManyToOne @JoinColumn(name="user_id") private User user; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getText() { return text; } public void setText(String text) {
  • 35. 31 | P a g e this.text = text; } public SimpleQuestion getSimpleQuestion() { return simpleQuestion; } public void setSimpleQuestion(SimpleQuestion simpleQuestion) { this.simpleQuestion = simpleQuestion; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } } 3.9. ChoiceAnswer package com.abahhar.formsapp.domain; import javax.persistence.*; @Entity @Table(name="choiceanswers") public class ChoiceAnswer { @Id @GeneratedValue private Integer id; public ChoiceAnswer(){ } //---------------------------------Navigation properties------- --------------------------// @ManyToOne @JoinColumn(name="question_id") private MCQuestion mcQuestion; @ManyToOne @JoinColumn(name="choice_id") private Choice choice; @ManyToOne @JoinColumn(name="user_id") private User user; public Integer getId() { return id; } public void setId(Integer id) { this.id = id;
  • 36. 32 | P a g e } public MCQuestion getMcQuestion() { return mcQuestion; } public void setMcQuestion(MCQuestion mcQuestion) { this.mcQuestion = mcQuestion; } public Choice getChoice() { return choice; } public void setChoice(Choice choice) { this.choice = choice; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } }
  • 37. 33 | P a g e 4. Repositories In this section, we create interfaces for the repositories that we will be using. Repositories are used for the data access, this gives us a good separation of the data access logic so we do not bother ourselves with when writing the logic. Also, all the interfaces that we will be creating extend a ready interface that is called JpaRepository, which we specify for it the type that we are dealing with and the type of its primary key. JpaRepository includes many built in methods that will help us in inserting, updating and deleting the entity we are dealing with, which saves our time, because we will not need to write anything for doing any transaction to the database. 4.1. UserRepository package com.abahhar.formsapp.repository; import org.springframework.data.jpa.repository.JpaRepository; import com.abahhar.formsapp.domain.User; public interface UserRepository extends JpaRepository<User, Integer> { public User findByLogin(String login); } 4.2. RoleRepository package com.abahhar.formsapp.repository; import org.springframework.data.jpa.repository.JpaRepository; import com.abahhar.formsapp.domain.Question; public interface QuestionRepository<T extends Question> extends JpaRepository<T, Integer> { } 4.3. FormRepository package com.abahhar.formsapp.repository; import org.springframework.data.jpa.repository.JpaRepository; import com.abahhar.formsapp.domain.Form; public interface FormRepository extends JpaRepository<Form, Integer> { }
  • 38. 34 | P a g e 4.4. QuestionRepository package com.abahhar.formsapp.repository; import org.springframework.data.jpa.repository.JpaRepository; import com.abahhar.formsapp.domain.Question; public interface QuestionRepository<T extends Question> extends JpaRepository<T, Integer> { } 4.5. SimpleQuestionRepository package com.abahhar.formsapp.repository; import com.abahhar.formsapp.domain.SimpleQuestion; public interface SimpleQuestionRepository extends QuestionRepository<SimpleQuestion> { } 4.6. MCQuestionRepository package com.abahhar.formsapp.repository; import com.abahhar.formsapp.domain.MCQuestion; public interface MCQuestionRepository extends QuestionRepository<MCQuestion> { } 4.7. ChoiceRepository package com.abahhar.formsapp.repository; import org.springframework.data.jpa.repository.JpaRepository; import com.abahhar.formsapp.domain.Choice; public interface ChoiceRepository extends JpaRepository<Choice, Integer> { }
  • 39. 35 | P a g e 4.8. SimpleAnswerRepository package com.abahhar.formsapp.repository; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; import com.abahhar.formsapp.domain.SimpleAnswer; import com.abahhar.formsapp.domain.SimpleQuestion; import com.abahhar.formsapp.domain.User; public interface SimpleAnswerRepository extends JpaRepository<SimpleAnswer, Integer> { } 4.9. ChoiceAnswerRepository package com.abahhar.formsapp.repository; import org.springframework.data.jpa.repository.JpaRepository; import com.abahhar.formsapp.domain.ChoiceAnswer; public interface ChoiceAnswerRepository extends JpaRepository<ChoiceAnswer, Integer> { } 5. Services In this section, we create the needed services to be used in the application. Services provide us a good separation of the business logic that we need. Controllers use the services, and the services use repositories, and with this we have a good separation of concerns. Please make sure that the services are in “com.abahhar.formsapp.service” package. 5.1. CustomUserDetailsService package com.abahhar.formsapp.service; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService;
  • 40. 36 | P a g e import org.springframework.security.core.userdetails.UsernameNotFoundExcepti on; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.abahhar.formsapp.repository.UserRepository; @Service @Transactional(readOnly=true) public class CustomUserDetailsService implements UserDetailsService { @Autowired private UserRepository userRepository; public UserDetails loadUserByUsername(String login) throws UsernameNotFoundException { com.abahhar.formsapp.domain.User domainUser = userRepository.findByLogin(login); boolean enabled = true; boolean accountNonExpired = true; boolean credentialsNonExpired = true; boolean accountNonLocked = true; return new User( domainUser.getLogin(), domainUser.getPassword(), enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, getAuthorities(domainUser.getRole().getId()) ); } public Collection<? extends GrantedAuthority> getAuthorities(Integer role) { List<GrantedAuthority> authList = getGrantedAuthorities(getRoles(role)); return authList; } public List<String> getRoles(Integer role) { List<String> roles = new ArrayList<String>(); if (role.intValue() == 1) { roles.add("ROLE_USER"); roles.add("ROLE_ADMIN"); } else if (role.intValue() == 2) { roles.add("ROLE_USER"); } return roles; } public static List<GrantedAuthority> getGrantedAuthorities(List<String> roles) { List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
  • 41. 37 | P a g e for (String role : roles) { authorities.add(new SimpleGrantedAuthority(role)); } return authorities; } } This service will be used by Spring Security to do everything about authentication and authorization with respect to the database. Also, it is the one specified in the spring- security.xml configuration in the fragment of code: <security:authentication-manager> <security:authentication-provider user-service- ref="customUserDetailsService"> <security:password-encoder hash="sha" /> </security:authentication-provider> </security:authentication-manager> Notice that the service is annotated with @Service annotations, to declare it as a Spring Component, and it will be scanned for dependency injection. Furthermore, @Transactional annotation is used. For information about this annotation, please refer to the following link: http://stackoverflow.com/questions/15300483/some-clarification-about-spring- transactional-annotation-on-a-method
  • 42. 38 | P a g e 5.2. UserService package com.abahhar.formsapp.service; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.apache.commons.codec.digest.DigestUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.abahhar.formsapp.domain.Role; import com.abahhar.formsapp.domain.User; import com.abahhar.formsapp.repository.RoleRepository; import com.abahhar.formsapp.repository.UserRepository; @Service @Transactional public class UserService { @Autowired private UserRepository userRepository; @Autowired private RoleRepository roleRepository; public User getUser(String login){ return userRepository.findByLogin(login); } public boolean registerUser(User user){ User loadedUser = userRepository.findByLogin(user.getLogin()); if(loadedUser != null){ return false; } String hashedPassword = DigestUtils.sha1Hex(user.getPassword()); Role role = roleRepository.findOne(2); List<User> usersList = userRepository.findAll(); Set<User> userRoles = new HashSet<User>(); Iterator<User> iterator = usersList.iterator(); while(iterator.hasNext()){ User userRole = iterator.next(); //The admin doesn't need to have the ROLE_USER, only users if(userRole.getRole().getId() != 1){ userRoles.add(userRole); } } userRoles.add(user); role.setUserRoles(userRoles);
  • 43. 39 | P a g e user.setPassword(hashedPassword); roleRepository.save(role); return true; } } This service is what we will use in the controllers to deal with users, as you notice, we use two repositories here which are: UserRepository and RoleRepository. The repositories are automatically injected by the framework since annotated with @Autowired. Also, we have two methods: getUser, which retrieves for us a user by his username, and registerUser, which registers a user. Please notice that in the registerUser we encrypt the password with sha1 encryption, and we add the user role for the registered user, then save it in the database using the repository. 5.3. RoleService package com.abahhar.formsapp.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.abahhar.formsapp.domain.Role; import com.abahhar.formsapp.repository.RoleRepository; @Service @Transactional public class RoleService { @Autowired private RoleRepository roleRepository; public Role getRole(int id){ return roleRepository.findOne(id); } }
  • 44. 40 | P a g e 5.4. FormService package com.abahhar.formsapp.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.abahhar.formsapp.domain.Form; import com.abahhar.formsapp.repository.FormRepository; @Service @Transactional public class FormService { @Autowired private FormRepository formRepository; public Iterable<Form> findAll() { return formRepository.findAll(); } public Form save(Form entity) { return formRepository.save(entity); } public void delete(Integer id) { formRepository.delete(id); } public Form findOne(Integer id) { return formRepository.findOne(id); } } 5.5. SimpleQuestionService package com.abahhar.formsapp.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.abahhar.formsapp.domain.SimpleQuestion; import com.abahhar.formsapp.repository.SimpleQuestionRepository; @Service @Transactional public class SimpleQuestionService { @Autowired private SimpleQuestionRepository simpleQuestionRepository; public Iterable<SimpleQuestion> findAll() { return simpleQuestionRepository.findAll(); } public SimpleQuestion save(SimpleQuestion entity) { return simpleQuestionRepository.save(entity);
  • 45. 41 | P a g e } public void delete(Integer id) { simpleQuestionRepository.delete(id); } public SimpleQuestion findOne(Integer id) { return simpleQuestionRepository.findOne(id); } } 5.6. MCQuestionService package com.abahhar.formsapp.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.abahhar.formsapp.domain.MCQuestion; import com.abahhar.formsapp.repository.MCQuestionRepository; @Service @Transactional public class MCQuestionService { @Autowired private MCQuestionRepository mcQuestionRepository; public Iterable<MCQuestion> findAll() { return mcQuestionRepository.findAll(); } public MCQuestion save(MCQuestion entity) { return mcQuestionRepository.save(entity); } public void delete(Integer id) { mcQuestionRepository.delete(id); } public MCQuestion findOne(Integer id) { return mcQuestionRepository.findOne(id); } }
  • 46. 42 | P a g e 5.7. ChoiceService package com.abahhar.formsapp.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.abahhar.formsapp.domain.Choice; import com.abahhar.formsapp.repository.ChoiceRepository; @Service @Transactional public class ChoiceService { @Autowired private ChoiceRepository choiceRepository; public Iterable<Choice> findAll() { return choiceRepository.findAll(); } public Choice save(Choice entity) { return choiceRepository.save(entity); } public void delete(Integer id) { choiceRepository.delete(id); } public Choice findOne(Integer id) { return choiceRepository.findOne(id); } } 5.8. SimpleAnswerService package com.abahhar.formsapp.service; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.abahhar.formsapp.domain.SimpleAnswer; import com.abahhar.formsapp.domain.SimpleQuestion; import com.abahhar.formsapp.domain.User; import com.abahhar.formsapp.repository.SimpleAnswerRepository; @Service @Transactional public class SimpleAnswerService { @Autowired private SimpleAnswerRepository simpleAnswerRepository; public Iterable<SimpleAnswer> findAll() { return simpleAnswerRepository.findAll();
  • 47. 43 | P a g e } public SimpleAnswer save(SimpleAnswer entity) { return simpleAnswerRepository.save(entity); } public void delete(Integer id) { simpleAnswerRepository.delete(id); } public SimpleAnswer findOne(Integer id) { return simpleAnswerRepository.findOne(id); } } 5.9. ChoiceAnswerService package com.abahhar.formsapp.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.abahhar.formsapp.domain.ChoiceAnswer; import com.abahhar.formsapp.repository.ChoiceAnswerRepository; @Service @Transactional public class ChoiceAnswerService { @Autowired private ChoiceAnswerRepository choiceAnswerRepository; public Iterable<ChoiceAnswer> findAll() { return choiceAnswerRepository.findAll(); } public ChoiceAnswer save(ChoiceAnswer entity) { return choiceAnswerRepository.save(entity); } public void delete(Integer id) { choiceAnswerRepository.delete(id); } public ChoiceAnswer findOne(Integer id) { return choiceAnswerRepository.findOne(id); } }
  • 48. 44 | P a g e 6. MCQuestion Wrapper Class MCQuestionWrapper is a wrapper class that we will be using later in MCQuestionController, to avoid any errors later, please make sure that this class exist in “com.abahhar.formsapp.wrapper” package. This class wraps an MCQuestion with the list of choices. package com.abahhar.formsapp.wrapper; import java.util.ArrayList; import java.util.List; import com.abahhar.formsapp.domain.Choice; import com.abahhar.formsapp.domain.Form; import com.abahhar.formsapp.domain.MCQuestion; public class MCQuestionWrapper { private MCQuestion mcQuestion; private List<Choice> choices; public MCQuestionWrapper(){ this.mcQuestion = new MCQuestion(); this.choices = new ArrayList<Choice>(); } public MCQuestion getMcQuestion() { return mcQuestion; } public void setMcQuestion(MCQuestion mcQuestion) { this.mcQuestion = mcQuestion; } public List<Choice> getChoices() { return choices; } public void setChoices(List<Choice> choices) { this.choices = choices; } }
  • 49. 45 | P a g e 7. Controllers In this section, we create the proper controllers for the web application with proper actions. Please make sure that the controllers are in “com.abahhar.formsapp.controller” package, except for HomeController, which is in “com.abahhar.formsapp” package. 7.1. Home Controller package com.abahhar.formsapp; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.servlet.ModelAndView; /** * Handles requests for the application home page. */ @Controller public class HomeController { /** * Simply selects the home view to render by returning its name. */ @RequestMapping(value = "/", method = RequestMethod.GET) public ModelAndView home() { return new ModelAndView("redirect:/forms"); } } This controller contains the action home(), which you could access by going to URL localhost/. The mapping of the URL to the action is specified by the value attribute in the data annotation @RequestMapping, and the method specified is GET method. This action redirects the user to “localhost/forms”. As you notice, the action returns ModelAndView, which is a type that enables you to specify the path for the view to return to, and enables you to include models and data to be returned to the view. Another thing to notice is that if you want the Spring Framework to know that the class is a Spring Controller “Component”, then you must put @Controller annotation on the controller as done in this fragment of code, and you will notice in the package explorer, the icon of the file will have a blue S on it, which means that this is a Spring Component.
  • 50. 46 | P a g e 7.2. SecurityNavigation Controller This controller will handle the navigation for login, success-login and logout actions, because we are using Spring MVC, we should make the controller with URL mappings to the desired procedures, and this is what we are doing here: package com.abahhar.formsapp.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.servlet.ModelAndView; import com.abahhar.formsapp.domain.User; import com.abahhar.formsapp.service.UserService; @Controller public class SecurityNavigation { @Autowired UserService userService; @RequestMapping(value="/user-login", method=RequestMethod.GET) public ModelAndView loginForm() { return new ModelAndView("login-form"); } @RequestMapping(value="/error-login", method=RequestMethod.GET) public ModelAndView invalidLogin() { ModelAndView modelAndView = new ModelAndView("login-form"); modelAndView.addObject("error", true); return modelAndView; } @RequestMapping(value="/success-login", method=RequestMethod.GET) public ModelAndView successLogin() { return new ModelAndView("success-login"); } @RequestMapping(value="/users/register", method=RequestMethod.GET) public ModelAndView register(){ return new ModelAndView("users/register"); } @RequestMapping(value="/users/register", method=RequestMethod.POST) public ModelAndView register(@ModelAttribute("user") User use if(!userService.registerUser(user)){ return new ModelAndView("users/register").addObject("error", true); } return new ModelAndView("login-form").addObject("registered", true);} } As you notice, the controller contains proper actions for login, success-login, logout and register. Also, you notice that we have UserService which is annotated with @Autowired. @ModelAttribute is used to set the name of the entity that is got from the form in the view, the name of the entity should be contained in the name attribute of the form tag.
  • 51. 47 | P a g e 7.3. FormsController package com.abahhar.formsapp.controller; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; import com.abahhar.formsapp.domain.Form; import com.abahhar.formsapp.domain.MCQuestion; import com.abahhar.formsapp.domain.Question; import com.abahhar.formsapp.domain.SimpleQuestion; import com.abahhar.formsapp.service.FormService; @Controller public class FormsController { @Autowired private FormService formService; @RequestMapping(value="/forms", method=RequestMethod.GET) public ModelAndView index(){ ModelAndView modelAndView = new ModelAndView("forms/index"); modelAndView.addObject("forms", formService.findAll()); return modelAndView; } @RequestMapping(value="/forms/details", method=RequestMethod.GET) public ModelAndView details(@RequestParam Integer id){ ModelAndView modelAndView = new ModelAndView("forms/details"); Form form = formService.findOne(id); Set<SimpleQuestion> simpleQuestions = new HashSet<SimpleQuestion>(); Set<MCQuestion> mcQuestions = new HashSet<MCQuestion>(); Iterator<Question> iterator = form.getQuestions().iterator(); while(iterator.hasNext()){ Question question = iterator.next(); if(question instanceof SimpleQuestion){ SimpleQuestion simpleQuestion = (SimpleQuestion) question; simpleQuestions.add(simpleQuestion); }else{ MCQuestion mcQuestion = (MCQuestion) question;
  • 52. 48 | P a g e mcQuestions.add(mcQuestion); } } modelAndView.addObject("form", formService.findOne(id)); modelAndView.addObject("simpleQuestions", simpleQuestions); modelAndView.addObject("mcQuestions", mcQuestions); return modelAndView; } @RequestMapping(value="/forms/create", method=RequestMethod.GET) public String create(){ return "forms/create"; } @RequestMapping(value="/forms/create", method=RequestMethod.POST) @ResponseBody public ModelAndView create(@ModelAttribute("form") Form form){ formService.save(form); return new ModelAndView("redirect:/forms"); } @RequestMapping(value="/forms/update", method=RequestMethod.GET) public ModelAndView update(@RequestParam Integer id){ ModelAndView modelAndView = new ModelAndView("forms/edit"); modelAndView.addObject("form", formService.findOne(id)); return modelAndView; } @RequestMapping(value="/forms/update", method=RequestMethod.POST) public ModelAndView update(@ModelAttribute("form") Form form){ ModelAndView modelAndView = new ModelAndView("redirect:/forms/details?id="+form.getId().toString()); formService.save(form); return modelAndView; } @RequestMapping(value="/forms/delete", method=RequestMethod.GET) public ModelAndView delete(@RequestParam Integer id){ ModelAndView modelAndView = new ModelAndView("redirect:/forms"); formService.delete(id); return modelAndView; } }
  • 53. 49 | P a g e The new thing here is @RequestParam annotation, this is used to specify that a variable is got from the string parameters (e.g. /forms/update?id=1). Another thing to notice is that when inserting and updating an entity, we use the save method from the service. The save method could insert and update at the same time because of the id of the entity, if the id doesn’t exist in the table, then the entity is new and will be inserted, but if the id exists, it will update the existed one. All this is handled automatically in the repository. 7.4. SimpleQuestionsController package com.abahhar.formsapp.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; import com.abahhar.formsapp.domain.Form; import com.abahhar.formsapp.domain.SimpleQuestion; import com.abahhar.formsapp.service.FormService; import com.abahhar.formsapp.service.SimpleQuestionService; @Controller public class SimpleQuestionsController { @Autowired private SimpleQuestionService simpleQuestionService; @Autowired private FormService formService; @RequestMapping(value="/simpleQuestions/details", method=RequestMethod.GET) public ModelAndView details(@RequestParam Integer id){ ModelAndView modelAndView = new ModelAndView("simpleQuestions/details"); modelAndView.addObject("simpleQuestion", simpleQuestionService.findOne(id)); return modelAndView; } @RequestMapping(value="/simpleQuestions/create", method=RequestMethod.GET) public ModelAndView create(@RequestParam Integer formId){ ModelAndView modelAndView = new ModelAndView("simpleQuestions/create"); modelAndView.addObject("form", formService.findOne(formId)); return modelAndView; }
  • 54. 50 | P a g e @RequestMapping(value="/simpleQuestions/create", method=RequestMethod.POST) @ResponseBody public ModelAndView create(@ModelAttribute("simpleQuestion") SimpleQuestion simpleQuestion){ simpleQuestionService.save(simpleQuestion); return new ModelAndView("redirect:/forms/details?id="+simpleQuestion.getForm().g etId().toString()); } @RequestMapping(value="/simpleQuestions/update", method=RequestMethod.GET) public ModelAndView update(@RequestParam Integer id){ ModelAndView modelAndView = new ModelAndView("simpleQuestions/edit"); modelAndView.addObject("simpleQuestion", simpleQuestionService.findOne(id)); return modelAndView; } @RequestMapping(value="/simpleQuestions/update", method=RequestMethod.POST) public ModelAndView update(@ModelAttribute("simpleQuestion") SimpleQuestion simpleQuestion){ simpleQuestion = simpleQuestionService.save(simpleQuestion); ModelAndView modelAndView = new ModelAndView("redirect:/forms/details?id="+simpleQuestion.getForm().g etId().toString()); return modelAndView; } @RequestMapping(value="/simpleQuestions/delete", method=RequestMethod.GET) public ModelAndView delete(@RequestParam Integer id){ Integer formId = simpleQuestionService.findOne(id).getForm().getId(); ModelAndView modelAndView = new ModelAndView("redirect:/forms/details?id="+formId.toString()); simpleQuestionService.delete(id); return modelAndView; } }
  • 55. 51 | P a g e 7.5. MCQuestionsController package com.abahhar.formsapp.controller; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Set; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; import com.abahhar.formsapp.domain.Choice; import com.abahhar.formsapp.domain.Form; import com.abahhar.formsapp.domain.MCQuestion; import com.abahhar.formsapp.domain.SimpleQuestion; import com.abahhar.formsapp.service.ChoiceService; import com.abahhar.formsapp.service.FormService; import com.abahhar.formsapp.service.MCQuestionService; import com.abahhar.formsapp.wrapper.MCQuestionWrapper; @Controller public class MCQuestionsController { @Autowired private MCQuestionService mcQuestionService; @Autowired private ChoiceService choiceService; @Autowired private FormService formService; @RequestMapping(value="/mcQuestions/details", method=RequestMethod.GET) public ModelAndView details(@RequestParam Integer id){ ModelAndView modelAndView = new ModelAndView("mcQuestions/details"); modelAndView.addObject("mcQuestion", mcQuestionService.findOne(id)); return modelAndView; } @RequestMapping(value="/mcQuestions/create", method=RequestMethod.GET) public ModelAndView create(@RequestParam Integer formId){ ModelAndView modelAndView = new ModelAndView("mcQuestions/create"); MCQuestionWrapper mcQuestionWrapper = new MCQuestionWrapper(); //add 4 choices to be filled for(int i = 1; i <= 4; i++){ mcQuestionWrapper.getChoices().add(new Choice());
  • 56. 52 | P a g e } modelAndView.addObject("form", formService.findOne(formId)); modelAndView.addObject("mcQuestionWrapper", mcQuestionWrapper); return modelAndView; } @RequestMapping(value="/mcQuestions/create", method=RequestMethod.POST) @ResponseBody public ModelAndView create(@ModelAttribute("mcQuestionWrapper") MCQuestionWrapper mcQuestionWrapper){ MCQuestion mcQuestion = mcQuestionWrapper.getMcQuestion(); List<Choice> choices = mcQuestionWrapper.getChoices(); mcQuestionService.save(mcQuestion); Iterator<Choice> iterator = choices.iterator(); while(iterator.hasNext()){ Choice choice = iterator.next(); choice.setMcQuestion(mcQuestion); choiceService.save(choice); } return new ModelAndView("redirect:/forms/details?id="+mcQuestion.getForm().getId ().toString()); } @RequestMapping(value="/mcQuestions/update", method=RequestMethod.GET) public ModelAndView update(@RequestParam Integer id){ ModelAndView modelAndView = new ModelAndView("mcQuestions/edit"); MCQuestionWrapper mcQuestionWrapper = new MCQuestionWrapper(); MCQuestion mcQuestion = mcQuestionService.findOne(id); mcQuestionWrapper.setMcQuestion(mcQuestion); Set<Choice> choices = mcQuestion.getChoices(); List<Choice> choicesList = new ArrayList<Choice>(); for(Iterator<Choice> iterator = choices.iterator(); iterator.hasNext(); ){ choicesList.add(iterator.next()); } mcQuestionWrapper.setChoices(choicesList); modelAndView.addObject("mcQuestionWrapper", mcQuestionWrapper); return modelAndView; }
  • 57. 53 | P a g e @RequestMapping(value="/mcQuestions/update", method=RequestMethod.POST) public ModelAndView update(@ModelAttribute("mcQuestionWrapper") MCQuestionWrapper mcQuestionWrapper){ MCQuestion mcQuestion = mcQuestionWrapper.getMcQuestion(); List<Choice> choices = mcQuestionWrapper.getChoices(); mcQuestionService.save(mcQuestion); mcQuestion = mcQuestionService.findOne(mcQuestion.getId()); Iterator<Choice> iterator = mcQuestion.getChoices().iterator(); while(iterator.hasNext()){ Integer choiceId = iterator.next().getId(); choiceService.delete(choiceId); } iterator = choices.iterator(); while(iterator.hasNext()){ Choice choice = iterator.next(); choice.setMcQuestion(mcQuestion); choiceService.save(choice); } return new ModelAndView("redirect:/forms/details?id="+mcQuestion.getForm().getId ().toString()); } @RequestMapping(value="/mcQuestions/delete", method=RequestMethod.GET) public ModelAndView delete(@RequestParam Integer id){ Integer formId = mcQuestionService.findOne(id).getForm().getId(); ModelAndView modelAndView = new ModelAndView("redirect:/forms/details?id="+formId.toString()); mcQuestionService.delete(id); return modelAndView; } }
  • 58. 54 | P a g e 7.6. SimpleAnswerController package com.abahhar.formsapp.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; import com.abahhar.formsapp.domain.SimpleAnswer; import com.abahhar.formsapp.domain.SimpleQuestion; import com.abahhar.formsapp.domain.User; import com.abahhar.formsapp.service.SimpleAnswerService; import com.abahhar.formsapp.service.SimpleQuestionService; import com.abahhar.formsapp.service.UserService; @Controller public class SimpleAnswersController { @Autowired private SimpleAnswerService simpleAnswerService; @Autowired private SimpleQuestionService simpleQuestionService; @Autowired UserService userService; @RequestMapping(value="/simpleAnswers/create", method=RequestMethod.POST) @ResponseBody public ModelAndView create(@ModelAttribute("simpleAnswer") SimpleAnswer simpleAnswer){ ModelAndView modelAndView = new ModelAndView("redirect:/simpleQuestions/details?id="+simpleAnswer.get SimpleQuestion().getId().toString()); String login = SecurityContextHolder.getContext().getAuthentication().getName(); User user = userService.getUser(login); simpleAnswer.setUser(user); SimpleQuestion simpleQuestion = simpleQuestionService.findOne(simpleAnswer.getSimpleQuestion().getId( )); simpleAnswer.setSimpleQuestion(simpleQuestion); simpleAnswerService.save(simpleAnswer); return modelAndView; } @RequestMapping(value="/simpleAnswers/delete", method=RequestMethod.GET)
  • 59. 55 | P a g e public ModelAndView delete(@RequestParam Integer answerId, @RequestParam Integer questionId){ ModelAndView modelAndView = new ModelAndView("redirect:/simpleQuestions/details?id="+questionId); simpleAnswerService.delete(answerId); return modelAndView; } } The new thing here is that we are using the following statement to get the username of the current user: String login = SecurityContextHolder.getContext().getAuthentication().getName(); Which with we get the entity of the user and set it to the simple answer, and because of this assignment, the foreign key of the user id is set automatically after saving the simple answer. 7.7. ChoiceAnswerController package com.abahhar.formsapp.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; import com.abahhar.formsapp.domain.ChoiceAnswer; import com.abahhar.formsapp.domain.MCQuestion; import com.abahhar.formsapp.domain.User; import com.abahhar.formsapp.service.ChoiceAnswerService; import com.abahhar.formsapp.service.MCQuestionService; import com.abahhar.formsapp.service.UserService; @Controller public class ChoiceAnswersController { @Autowired private ChoiceAnswerService choiceAnswerService; @Autowired private MCQuestionService mcQuestionService; @Autowired UserService userService;
  • 60. 56 | P a g e @RequestMapping(value="/choiceAnswers/create", method=RequestMethod.POST) @ResponseBody public ModelAndView create(@ModelAttribute("choiceAnswer") ChoiceAnswer choiceAnswer){ ModelAndView modelAndView = new ModelAndView("redirect:/mcQuestions/details?id="+choiceAnswer.getMcQu estion().getId().toString()); String login = SecurityContextHolder.getContext().getAuthentication().getName(); User user = userService.getUser(login); choiceAnswer.setUser(user); MCQuestion mcQuestion = mcQuestionService.findOne(choiceAnswer.getMcQuestion().getId()); choiceAnswer.setMcQuestion(mcQuestion); choiceAnswerService.save(choiceAnswer); return modelAndView; } @RequestMapping(value="/choiceAnswers/delete", method=RequestMethod.GET) public ModelAndView delete(@RequestParam Integer answerId, @RequestParam Integer questionId){ ModelAndView modelAndView = new ModelAndView("redirect:/mcQuestions/details?id="+questionId); choiceAnswerService.delete(answerId); return modelAndView; } }
  • 61. 57 | P a g e 8. Views 8.1. login-form.jsp <div class="container"> <h2 class="text-center">Login</h2> <c:if test="${error == true}"> <p> <b class="text-danger">Invalid login or password.</b> </p> </c:if> <c:if test="${registered == true}"> <p> <b class="text-success">Successfully registered, please enter credentials to login.</b> </p> </c:if> <form class="form-horizontal" role="form" method="POST" action="<c:url value="/j_spring_security_check"/>" > <div class="form-group"> <label class="control-label col-sm-2" for="j_username">Username:</label> <div class="col-sm-10"> <input type="text" class="form-control" name="j_username" id="j_username" placeholder="Enter username" autofocus> </div> </div> <div class="form-group"> <label class="control-label col-sm-2" for="j_password">Password:</label> <div class="col-sm-10"> <input type="password" class="form-control" name="j_password" id="j_password" placeholder="Enter password"> </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <button type="submit" class="btn btn- default">Login</button> </div> </div> </form> Here we have two if statements, one to check the value of error, and the other to check the value of registered. These two values are returned from the controller through the statements with the following signature “modelAndView.addObject(“NameOfVariable”, valueOfVariable)”. If the if statement is satisfied, the content inside the tag will be written in the output. <c:url /> tag is used to evaluate a statement that contains the current URL, followed by the value of the “value” attribute.
  • 62. 58 | P a g e Please notice that “j_username” and “j_password” are the names of variables that Spring Security deal with when passing the arguments from the views. 8.2. Users 8.2.1. Register.jsp <div class="container"> <h2 class="text-center">Registration form</h2> <c:if test="${error == true}"> <p> <b class="text-danger">Username already exists.</b> </p> </c:if> <form class="form-horizontal" role="form" name="user" method="POST" action="<c:url value="/users/register"/>" > <div class="form-group"> <label class="control-label col-sm-2" for="login">Username:</label> <div class="col-sm-10"> <input type="text" class="form-control" name="login" id="login" placeholder="Enter username" autofocus> </div> </div> <div class="form-group"> <label class="control-label col-sm-2" for="password">Password:</label> <div class="col-sm-10"> <input type="password" class="form-control" name="password" id="password" placeholder="Enter password"> </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <button type="submit" class="btn btn- default">Register</button> </div> </div> </form>
  • 63. 59 | P a g e 8.3. Forms 8.3.1. index.jsp <sec:authorize access="hasRole('ROLE_ADMIN')"> <p> <a href="<c:url value="/forms/create"/>" class="btn btn-default btn-lg">Create form</a> </p> </sec:authorize> <!-- Title --> <div class="row"> <div class="col-lg-12"> <h3>Latest Forms</h3> </div> </div> <!-- /.row --> <c:choose> <c:when test="${not empty forms }"> <!-- Page Features --> <div class="row text-center"> <c:forEach var="form" items="${forms}"> <a href="<c:url value="forms/details?id=${form.id}" />"> <div class="col-md-3 col-sm-6 hero- feature"> <div class="thumbnail"> <img src="<c:url value="/resources/img/form-icon.png" />" alt=""> <div class="caption"> <h3>${form.title}</h3> <sec:authorize access="hasRole('ROLE_ADMIN')"> <p> <a href="<c:url value="forms/update?id=${form.id}"/>" class="btn btn- primary">Edit</a> <a href="<c:url value="forms/delete?id=${form.id}"/>" class="btn btn- default">Delete</a> </p> </sec:authorize> </div> </div> </div> </a> </c:forEach> </div> <!-- /.row --> </c:when> <c:otherwise> There are no forms </c:otherwise> </c:choose>
  • 64. 60 | P a g e Here we checked the role of the user using the tag <sec:authorize>, we check if the user is with the role of admin, if the check is satisfied, the button for creating a form will be displayed in the output. Also, we used the tags <c:choose>, <c:when> and <c:otherwise>. When using the choose tag, when will behave as an if statement with the condition in the test attribute, and otherwise will behave as an else if the condition in the when tag is not satisfied. Furthermore, we use the tag <c:foreach> to loop through the list of forms we have got from the controller, we set each item in the list of forms to a variable which we called “form”, then we used the properties of the form to display them in the page. Please notice that to access the properties of an object in JSP pages, we include the name of the property in ${} (e.g. ${form.title}). Also, to use the authorize tag you should include this fragment of code after the declaration of the xml file <?xml version=”1.0” encoding=”UTF-9”?>: <%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
  • 65. 61 | P a g e 8.3.2. details.jsp <div class="container"> <h2 class="text-center">${form.title}</h2> <h4> <a href="<c:url value="/forms"/>">Back to forms</a> </h4> <sec:authorize access="hasRole('ROLE_ADMIN')"> <p> <a href="<c:url value="/simpleQuestions/create?formId=${form.id}"/>" class="btn btn- default btn-lg">Create simple question</a> <a href="<c:url value="/mcQuestions/create?formId=${form.id}"/>" class="btn btn- default btn-lg">Create multiple choice question</a> </p> </sec:authorize> <c:choose> <c:when test="${not empty simpleQuestions}"> <table class="table table-striped table-bordered" style="font-size: 18px"> <thead> <tr> <th>Simple questions</th> <sec:authorize access="hasRole('ROLE_ADMIN')"> <th colspan="2" class="text- center">Manage</th> </sec:authorize> </tr> </thead> <tbody> <c:forEach var="simpleQuestion" items="${simpleQuestions}"> <tr> <td style="padding: 10px"> <a href="<c:url value="../simpleQuestions/details?id=${simpleQuestion.id}" />" > ${simpleQuestion.text} </a> </td> <sec:authorize access="hasRole('ROLE_ADMIN')"> <td class="text-center"> <a href="<c:url value="../simpleQuestions/update?id=${simpleQuestion.id}" />" > Edit </a> </td> <td class="text-center"> <a href="<c:url value="../simpleQuestions/delete?id=${simpleQuestion.id}" />" > Delete </a> </td> </sec:authorize> </tr>
  • 66. 62 | P a g e </c:forEach> </tbody> </table> </c:when> <c:otherwise> <div class="well"> There are no written questions </div> </c:otherwise> </c:choose> <c:choose> <c:when test="${not empty mcQuestions}"> <table class="table table-striped table-bordered" style="font-size: 18px"> <thead> <tr> <th>Multiple choice questions</th> <sec:authorize access="hasRole('ROLE_ADMIN')"> <th colspan="2" class="text- center">Manage</th> </sec:authorize> </tr> </thead> <tbody> <c:forEach var="mcQuestion" items="${mcQuestions}"> <tr> <td style="padding: 10px"> <a href="<c:url value="../mcQuestions/details?id=${mcQuestion.id}" />" > ${mcQuestion.text} </a> </td> <sec:authorize access="hasRole('ROLE_ADMIN')"> <td class="text-center"> <a href="<c:url value="../mcQuestions/update?id=${mcQuestion.id}" />" > Edit </a> </td> <td class="text-center"> <a href="<c:url value="../mcQuestions/delete?id=${mcQuestion.id}" />" > Delete </a> </td> </sec:authorize> </tr> </c:forEach> </tbody> </table> </c:when> <c:otherwise> <div class="well"> There are no multiple choice questions