May 4th, 2023
JSP + Servlet + OAuth + Maven + MySQL
JSP application which does the authentication using the Google OAuth. Once logged in, it will get the details from the MySQL database.
4.0.0
com.brains
oauth
0.0.1-SNAPSHOT
war
oauth Maven Webapp
http://www.example.com
UTF-8
1.7
1.7
javax.servlet
javax.servlet-api
3.0.1
com.google.api-client
google-api-client
1.22.0
com.google.http-client
google-http-client
1.22.0
com.google.code.gson
gson
2.7
com.google.http-client
google-http-client-jackson
1.22.0
com.google.apis
google-api-services-oauth2
v2-rev120-1.22.0
com.google.api-client
google-api-client
1.22.0
com.google.apis
google-api-services-plus
v1-rev453-1.22.0
mysql
mysql-connector-java
8.0.33
org.apache.logging.log4j
log4j-api
2.20.0
org.apache.logging.log4j
log4j-core
2.20.0
oauth
maven-clean-plugin
3.1.0
maven-resources-plugin
3.0.2
maven-compiler-plugin
3.8.0
maven-surefire-plugin
2.22.1
maven-war-plugin
3.2.2
maven-install-plugin
2.5.2
maven-deploy-plugin
2.8.2
Archetype Created Web Application
database
oauth
user
root
password
root
com.brains.listeners.DatabaseContextListener
LoginServlet
LoginServlet
com.brains.LoginServlet
LoginServlet
/login
Servlet OAuth example
Servlet OAuth example
<%@ page isELIgnored="false" %>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
Welcome
<% if (session.getAttribute("ubName") == null) {%>
<% } %>
Welcome ${ubName}
Data from DB
Name${emp.name}
Mobile${emp.mobile}
Email${emp.email}
/* style.css */
@charset "UTF-8";
body {
font-family: Arial, Helvetica, sans-serif;
}
* {
box-sizing: border-box;
}
/* style the container */
.container {
position: relative;
border-radius: 5px;
background-color: #f2f2f2;
padding: 20px 0 30px 0;
}
/* style inputs and link buttons */
input,
.btn {
width: 100%;
padding: 12px;
border: none;
border-radius: 4px;
margin: 5px 0;
opacity: 0.85;
display: inline-block;
font-size: 17px;
line-height: 20px;
text-decoration: none; /* remove underline from anchors */
}
input:hover,
.btn:hover {
opacity: 1;
}
/* add appropriate colors to fb, twitter and google buttons */
.fb {
background-color: #3B5998;
color: white;
}
.twitter {
background-color: #55ACEE;
color: white;
}
.google {
background-color: #dd4b39;
color: white;
}
/* style the submit button */
input[type=submit] {
background-color: #04AA6D;
color: white;
cursor: pointer;
}
input[type=submit]:hover {
background-color: #45a049;
}
/* Two-column layout */
.col {
float: left;
width: 50%;
margin: auto;
padding: 0 50px;
margin-top: 6px;
}
/* Clear floats after the columns */
.row:after {
content: "";
display: table;
clear: both;
}
/* vertical line */
.vl {
position: absolute;
left: 50%;
transform: translate(-50%);
border: 2px solid #ddd;
height: 175px;
}
/* text inside the vertical line */
.vl-innertext {
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
background-color: #f1f1f1;
border: 1px solid #ccc;
border-radius: 50%;
padding: 8px 10px;
}
/* hide some text on medium and large screens */
.hide-md-lg {
display: none;
}
/* bottom container */
.bottom-container {
text-align: center;
background-color: #666;
border-radius: 0px 0px 4px 4px;
}
/* Responsive layout - when the screen is less than 650px wide, make the two columns stack on top of each other instead of next to each other */
@media screen and (max-width: 650px) {
.col {
width: 100%;
margin-top: 0;
}
/* hide the vertical line */
.vl {
display: none;
}
/* show the hidden text on small screens */
.hide-md-lg {
display: block;
text-align: center;
}
}
.m1{
width:300px;
}
.mytd{
border:1px solid black;
clear: both;
padding: 10px;
height: 30px;
}
.mytd>div{
float: left;
}
.label{
font-weight: 900;
padding-right:10px;
}
img{
width:100px;
height:100px;
}
%d{yyyy-MM-dd'T'HH:mm:ss.SSSZ} %p %m%n
package com.brains;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.brains.models.Employee;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
/**
* Servlet implementation class LoginServlet
*/
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private Connection conn;
private static final Logger LOGGER = LogManager.getLogger(LoginServlet.class);
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// TODO Auto-generated method stub
checkActiveSession(req, resp);
resp.setContentType("text/html");
try {
String idToken = req.getParameter("id_token");
GoogleIdToken.Payload payLoad = IdTokenVerifierAndParser.getPayload(idToken);
String name = (String) payLoad.get("name");
String email = payLoad.getEmail();
HttpSession session = req.getSession(true);
session.setAttribute("ubName", name);
req.setAttribute("email", email);
session.setAttribute("picture", payLoad.get("picture"));
getUserDetailsFromDB(req);
req.getServletContext()
.getRequestDispatcher("/welcome-page.jsp").forward(req, resp);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void getUserDetailsFromDB(ServletRequest req) {
if(conn == null) {
conn = (Connection) this.getServletContext().getAttribute("con");
}
String loginEmail = (String) req.getAttribute("email");
HttpSession session = ((HttpServletRequest) req).getSession(true);
String str = "SELECT * FROM employee where email = '"+loginEmail+"'";
try (
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(str)) {
// Extract data from result set
while (rs.next()) {
//Retrieve by column name
String name = rs.getString("name");
String email = rs.getString("email");
String mobile = rs.getString("mobile");
// Add item
Employee emp = new Employee(name, email, mobile);
session.setAttribute("emp", emp);
}
session.setAttribute("title", "Top 5 fruits");
// req.getRequestDispatcher("/WEB-INF/views/index.jsp").forward(req, resp);
} catch (SQLException se) {
se.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
checkActiveSession(req, resp);
req.getServletContext()
.getRequestDispatcher("/welcome-page.jsp").forward(req, resp);
}
private void checkActiveSession(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
HttpSession session = req.getSession();
String userName = (String) session.getAttribute("ubName");
LOGGER.warn("checkActiveSession: "+ userName);
if(userName == null) {
req.getRequestDispatcher("index.jsp").include(req, resp);
}
}
}
package com.brains;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.jackson2.JacksonFactory;
public class IdTokenVerifierAndParser {
private static final String GOOGLE_CLIENT_ID = "434006981147-vcaa735q92hmajglm2m7vbeb981p5h6t.apps.googleusercontent.com";
public static GoogleIdToken.Payload getPayload (String tokenString) throws Exception {
JacksonFactory jacksonFactory = new JacksonFactory();
GoogleIdTokenVerifier googleIdTokenVerifier =
new GoogleIdTokenVerifier(new NetHttpTransport(), jacksonFactory);
GoogleIdToken token = GoogleIdToken.parse(jacksonFactory, tokenString);
if (googleIdTokenVerifier.verify(token)) {
GoogleIdToken.Payload payload = token.getPayload();
if (!GOOGLE_CLIENT_ID.equals(payload.getAudience())) {
throw new IllegalArgumentException("Audience mismatch");
} else if (!GOOGLE_CLIENT_ID.equals(payload.getAuthorizedParty())) {
throw new IllegalArgumentException("Client ID mismatch");
}
return payload;
} else {
throw new IllegalArgumentException("id token cannot be verified");
}
}
}
package com.brains.models;
public class Employee {
private String name;
private String email;
private String mobile;
public Employee() {}
public Employee(String name, String email, String mobile) {
this.name = name;
this.email = email;
this.mobile = mobile;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
}
package com.brains.listeners;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.mysql.cj.jdbc.AbandonedConnectionCleanupThread;
public class DatabaseContextListener implements ServletContextListener {
private static final Logger LOGGER = LogManager.getLogger(DatabaseContextListener.class);
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext context = sce.getServletContext();
String JDBC_DRIVER = "com.mysql.cj.jdbc.Driver";
String DB_URL="jdbc:mysql://localhost:3307";
String database = context.getInitParameter("database");
String user = context.getInitParameter("user");
String password = context.getInitParameter("password");
try {
Class.forName(JDBC_DRIVER);
Connection con = DriverManager.getConnection(DB_URL+"/"+database+"?useSSL=false&allowPublicKeyRetrieval=true", user, password);
context.setAttribute("con", con);
} catch (SQLException | ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
Enumeration drivers = DriverManager.getDrivers();
Driver d = null;
while (drivers.hasMoreElements()) {
try {
d = drivers.nextElement();
DriverManager.deregisterDriver(d);
LOGGER.warn(String.format("Driver %s deregistered", d));
}
catch (SQLException ex) {
LOGGER.warn(String.format("Error deregistering driver %s", d), ex);
}
}
try {
AbandonedConnectionCleanupThread.checkedShutdown();
}
catch (Exception e) {
LOGGER.warn("SEVERE problem cleaning up: " + e.getMessage());
e.printStackTrace();
}
}
}
Related Tutorials
4.0.0
org.springframework.boot
spring-boot-starter-parent
3.0.2
com.brains.jpa.hibernate
jpa-hibernate-demo
0.0.1-SNAPSHOT
jpa-hibernate-demo
Demo project for Spring Boot
17
org.springframework.boot
spring-boot-starter-data-jpa
org.springframework.boot
spring-boot-starter-web
com.h2database
h2
runtime
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-maven-plugin
org.projectlombok
lombok
spring.datasource.url=jdbc:h2:mem:testdb;NON_KEYWORDS=USER;DB_CLOSE_ON_EXIT=FALSE
spring.h2.console.enabled=true
spring.jpa.defer-datasource-initialization=true
# Turn Statistics ON
#spring.jpa.properties.hibernate.generate_statistics=true
logging.level.org.hibernate.stat=debug
#logging.level.root=trace
# Show all queries
spring.jpa.show-sql=true
# Format the queries
spring.jpa.properties.hibernate.format_sql=true
package com.brains.jpa.hibernate.jpahibernatedemo.entity;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.OneToMany;
import lombok.AccessLevel;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
@Entity
@Data
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Course {
@Id
@GeneratedValue
private Long id;
@NonNull
private String name;
@Setter(AccessLevel.NONE)
@OneToMany(mappedBy = "course", fetch = FetchType.LAZY)
private List reviews = new ArrayList<>();
@ManyToMany(mappedBy = "courses")
@Setter(value = AccessLevel.NONE)
private List students = new ArrayList<>();
public void addStudent(Student student) {
this.students.add(student);
}
public void addReview(Review review) {
this.reviews.add(review);
}
public void removeReview(Review review) {
this.reviews.remove(review);
}
@UpdateTimestamp
private LocalDateTime lastUpdatedDate;
@CreationTimestamp
private LocalDateTime createdDate;
public Course(String name) {
this.name = name;
}
}
package com.brains.jpa.hibernate.jpahibernatedemo.entity;
import java.util.ArrayList;
import java.util.List;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinTable;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.OneToOne;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.ToString;
@Entity
@Data @NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@RequiredArgsConstructor
public class Student {
@Id
@GeneratedValue
private Long id;
@NonNull
@Column(nullable = false)
private String name;
@OneToOne(fetch = FetchType.LAZY)
private Passport passport;
@ToString.Exclude
@ManyToMany
@Setter(value = AccessLevel.NONE)
@JoinTable(name = "STUDENT_COURSE",
joinColumns = @JoinColumn(name = "STUDENT_ID"),
inverseJoinColumns = @JoinColumn(name = "COURSE_ID")
)
private List courses = new ArrayList<>();
public void addCourse(Course course) {
this.courses.add(course);
}
}
package com.brains.jpa.hibernate.jpahibernatedemo.entity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.OneToOne;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
@Entity
@Data @NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@RequiredArgsConstructor
public class Passport {
@Id
@GeneratedValue
private Long id;
@NonNull
@Column(nullable = false)
private String number;
@ToString.Exclude
@OneToOne(fetch = FetchType.LAZY, mappedBy = "passport")
private Student student;
}
package com.brains.jpa.hibernate.jpahibernatedemo.entity;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
@Entity
@Data @NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@RequiredArgsConstructor
public class Review {
@Id
@GeneratedValue
private Long id;
@NonNull
private String rating;
@NonNull
private String description;
@ToString.Exclude
@ManyToOne
private Course course;
}
insert into course(id, name, created_date, last_updated_date)
values(10001, 'JPA in 5 steps', LOCALTIMESTAMP, LOCALTIMESTAMP);
insert into course(id, name, created_date, last_updated_date)
values(10002, 'JDBC in 10 steps', LOCALTIMESTAMP, LOCALTIMESTAMP);
insert into course(id, name, created_date, last_updated_date)
values(10003, 'JPQL in 50 steps', LOCALTIMESTAMP, LOCALTIMESTAMP);
insert into passport(id, number)
values(40001,'E12345');
insert into passport(id, number)
values(40002,'F212345');
insert into passport(id, number)
values(40003,'GE23451');
insert into student(id, name, passport_id)
values(20001,'Ranga',40001);
insert into student(id, name, passport_id)
values(20002,'Adam',40002);
insert into student(id, name, passport_id)
values(20003,'Jane',40003);
insert into review(id, rating, description, course_id)
values(50001,'1', 'Great course', 10001);
insert into review(id, rating, description, course_id)
values(50002,'3', 'Nice course', 10001);
insert into review(id, rating, description, course_id)
values(50004,'5', 'Good you are writing', 10003);
insert into student_course(student_id, course_id)
values(20001, 10001);
insert into student_course(student_id, course_id)
values(20002, 10001);
insert into student_course(student_id, course_id)
values(20003, 10001);
insert into student_course(student_id, course_id)
values(20001, 10003);
package com.brains.jpa.hibernate.jpahibernatedemo;
import static org.junit.jupiter.api.Assertions.*;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import com.brains.jpa.hibernate.jpahibernatedemo.entity.Course;
import com.brains.jpa.hibernate.jpahibernatedemo.entity.Student;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import jakarta.transaction.Transactional;
@SpringBootTest(classes = JpaHibernateDemoApplication.class)
class JPQLQueryTest {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
EntityManager em;
// get course which do not have any student
// @Test
@Transactional
void jpql_courses_without_students() {
TypedQuery createQuery = em.createQuery("select c from Course c where c.students is empty", Course.class);
List resultList = createQuery.getResultList();
logger.info("Courses: -> {}", resultList);
}
// get courses where which has more thatn 2 students
// @Test
@Transactional
void jpql_courses_with_atleast_2_students() {
TypedQuery createQuery = em.createQuery("select c from Course c where size(c.students) > 2", Course.class);
List resultList = createQuery.getResultList();
logger.info("Courses: -> {}", resultList);
}
// get courses order by student size
// by default, order by is ascending(0-10)
// @Test
@Transactional
void jpql_courses_ordered_by_students() {
TypedQuery createQuery = em.createQuery("select c from Course c order by size(c.students) desc", Course.class);
List resultList = createQuery.getResultList();
logger.info("Courses: -> {}", resultList);
}
// get students whose passport number contains 12345
/**
* Other functions
* ===============
* like
* Between 100 and 500
* Is Null
*
* ---- On String ------
* upper, lower, trim, length
*/
@Test
@Transactional
void jpql_sudent_passport_matching() {
TypedQuery createQuery = em.createQuery("select s from Student s where s.passport.number like '%1234%'", Student.class);
List resultList = createQuery.getResultList();
logger.info("Courses: -> {}", resultList);
}
}
Leave a Reply