From c7d6b7edb9e4f3c6273c63faa7bd083f673d640c Mon Sep 17 00:00:00 2001 From: Lorenzo Ferron <20024182@studenti.uniupo.it> Date: Sun, 6 Dec 2020 01:46:40 +0100 Subject: [PATCH] Rinomina e aggiunta file sorgente. Rinominata la directory contenente i file sorgente per l'appendice. Aggiunti i file sorgenti. --- .../appendices/orm/assets/code/.gitkeep | 0 .../appendices/orm/assets/snippets/DAO.java | 87 +++++ .../appendices/orm/assets/snippets/Login.java | 95 +++++ .../orm/assets/snippets/LoginDAO.java | 22 ++ .../orm/assets/snippets/ResultSetMapper.java | 339 ++++++++++++++++++ .../orm/assets/snippets/Signup.java | 82 +++++ 6 files changed, 625 insertions(+) delete mode 100644 src/contents/appendices/orm/assets/code/.gitkeep create mode 100644 src/contents/appendices/orm/assets/snippets/DAO.java create mode 100644 src/contents/appendices/orm/assets/snippets/Login.java create mode 100644 src/contents/appendices/orm/assets/snippets/LoginDAO.java create mode 100644 src/contents/appendices/orm/assets/snippets/ResultSetMapper.java create mode 100644 src/contents/appendices/orm/assets/snippets/Signup.java diff --git a/src/contents/appendices/orm/assets/code/.gitkeep b/src/contents/appendices/orm/assets/code/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/contents/appendices/orm/assets/snippets/DAO.java b/src/contents/appendices/orm/assets/snippets/DAO.java new file mode 100644 index 0000000..f94e265 --- /dev/null +++ b/src/contents/appendices/orm/assets/snippets/DAO.java @@ -0,0 +1,87 @@ +package com.trimaral.dao; + +import com.google.i18n.phonenumbers.NumberParseException; +import com.trimaral.orm.ResultSetMapper; + +import javax.sql.DataSource; +import java.io.Serializable; +import java.sql.SQLException; +import java.util.List; + +/** + * @param <T> a DAO class + * @author Lorenzo Ferron + * @version 2019.09.07 + */ +public abstract class DAO<T extends Serializable> { + + protected final ResultSetMapper<T> resultSetMapper; + protected final DataSource dataSource; + + protected DAO(DataSource dataSource, Class<T> clazz) { + this.dataSource = dataSource; + this.resultSetMapper = new ResultSetMapper<>(dataSource, clazz); + } + + public static String getQuotedString(String s) { + return "'" + s + "'"; + } + + public List<T> findAll() throws SQLException, NumberParseException { + return findByCriteria(null); + } + + public List<T> findByCriteria(String criteria, Object... params) throws SQLException, NumberParseException { + return resultSetMapper.findByCriteria(criteria, params); + } + + public T findOneByCriteria(String criteria, Object... params) throws SQLException, NumberParseException { + resultSetMapper.getByCriteria(criteria, params); + try { + return findByCriteria(criteria, params).get(0); + } catch (IndexOutOfBoundsException e) { + return null; + } + } + + public T findById(Long id) throws SQLException, NumberParseException { + return findOneByCriteria(resultSetMapper.findById(), id); + } + + public void save(T item) throws SQLException, NumberParseException { + resultSetMapper.save(item, false, false); + } + + public void replace(T item) throws SQLException, NumberParseException { + resultSetMapper.save(item, true, false); + } + + public void update(T item) throws SQLException, NumberParseException { + resultSetMapper.update(item); + } + + public void updateByCriteria(T item, String criteria, Object... params) throws SQLException, NumberParseException { + resultSetMapper.updateByCriteria(item, criteria, params); + } + + public void updatesByCriteria(T[] items, String criteria, Object... params) throws SQLException, NumberParseException { + for (T item : items) + updateByCriteria(item, criteria, params); + } + + public void delete(T item) throws SQLException, NumberParseException { + resultSetMapper.delete(item); + } + + public void deleteByCriteria(String criteria, Object... params) throws SQLException, NumberParseException { + resultSetMapper.deleteByCriteria(criteria, params); + } + + public void deleteById(Long id) throws SQLException, NumberParseException { + resultSetMapper.deleteById(id); + } + + public Object customQuery(String query, Object... params) throws SQLException, NumberParseException { + return resultSetMapper.customQuery(query, params); + } +} diff --git a/src/contents/appendices/orm/assets/snippets/Login.java b/src/contents/appendices/orm/assets/snippets/Login.java new file mode 100644 index 0000000..6217df5 --- /dev/null +++ b/src/contents/appendices/orm/assets/snippets/Login.java @@ -0,0 +1,95 @@ +package com.trimaral.entity; + +import com.google.common.base.Preconditions; +import com.trimaral.orm.annotations.Column; +import com.trimaral.orm.annotations.Table; + +import java.io.Serializable; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +/** + * @author Lorenzo Ferron + * @version 2019.09.05 + */ +@Table(name = "login") +public class Login implements Serializable { + + public static final short PASSWORD_LENGTH = 8; + + @Column(name = "password") + private String password; + + @Column(name = "is_valid", hasDefaultValue = true) + private Boolean isValid; + + @Column(name = "login_id", isPrimaryKey = true) + private Long loginId; + + @Column(name = "email") + private String email; + + @Column(name = "enroll_date", hasDefaultValue = true, hold = true) + private Timestamp enrollDate; + + private List<EmailConfirmation> confirmations; + + public Login() { + confirmations = new ArrayList<>(0); + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + + public Boolean getIsValid() { + return isValid; + } + + public void setIsValid(Boolean isValid) { + this.isValid = isValid; + } + + + public Long getLoginId() { + return loginId; + } + + public void setLoginId(Long loginId) { + this.loginId = loginId; + } + + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + Preconditions.checkNotNull(email); + Preconditions.checkArgument(Pattern.compile("^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)])$", Pattern.CASE_INSENSITIVE).matcher(email).matches()); + this.email = email.trim(); + } + + public List<EmailConfirmation> getConfirmations() { + return confirmations; + } + + public void setConfirmations(List<EmailConfirmation> confirmations) { + this.confirmations = confirmations; + } + + public Timestamp getEnrollDate() { + return enrollDate; + } + + public void setEnrollDate(Timestamp enrollDate) { + this.enrollDate = enrollDate; + } +} diff --git a/src/contents/appendices/orm/assets/snippets/LoginDAO.java b/src/contents/appendices/orm/assets/snippets/LoginDAO.java new file mode 100644 index 0000000..0e40341 --- /dev/null +++ b/src/contents/appendices/orm/assets/snippets/LoginDAO.java @@ -0,0 +1,22 @@ +package com.trimaral.dao; + +import com.google.i18n.phonenumbers.NumberParseException; +import com.trimaral.entity.Login; + +import javax.sql.DataSource; +import java.sql.SQLException; + +/** + * @author Lorenzo Ferron + * @version 2019.09.05 + */ +public class LoginDAO extends DAO<Login> { + + public LoginDAO(DataSource dataSource) { + super(dataSource, Login.class); + } + + public Login findByEmail(String email) throws SQLException, NumberParseException { + return findOneByCriteria("email = " + getQuotedString(email)); + } +} diff --git a/src/contents/appendices/orm/assets/snippets/ResultSetMapper.java b/src/contents/appendices/orm/assets/snippets/ResultSetMapper.java new file mode 100644 index 0000000..c0f266d --- /dev/null +++ b/src/contents/appendices/orm/assets/snippets/ResultSetMapper.java @@ -0,0 +1,339 @@ +package com.trimaral.orm; + +import com.google.common.base.CharMatcher; +import com.google.common.collect.ObjectArrays; +import com.google.common.primitives.Primitives; +import com.google.i18n.phonenumbers.NumberParseException; +import com.trimaral.orm.annotations.Column; +import com.trimaral.orm.annotations.Table; +import com.trimaral.orm.exceptions.AnnotationNotFoundException; +import com.trimaral.orm.exceptions.DAOException; +import com.trimaral.orm.util.ClassUtil; + +import javax.sql.DataSource; +import java.lang.reflect.Field; +import java.sql.*; +import java.time.YearMonth; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.StringJoiner; + +/** + * @param <T> An entity class + * @author Lorenzo Ferron + * @version 2019.09.28 + */ +public class ResultSetMapper<T> { + + public static final String SET_CLAUSE = " SET "; + public static final String WHERE_CLAUSE = " WHERE "; + public static final String VALUES_CLAUSE = " VALUES "; + public static final String FROM_CLAUSE = " FROM "; + + public static final String SELECT_SQL = "SELECT *" + FROM_CLAUSE; + public static final String INSERT_SQL = "INSERT "; + public static final String IGNORE_SQL = "IGNORE "; + public static final String INTO_SQL = "INTO "; + public static final String UPDATE_SQL = "UPDATE "; + public static final String DELETE_SQL = "DELETE"; + public static final String DELIMITER = ", "; + private static final String REPLACE_SQL = " ON DUPLICATE KEY UPDATE "; + + private final DataSource dataSource; + private final Class<T> clazz; + private Table table; + private Field[] fields; + private List<Field> primaryKeyField = new ArrayList<>(0); + + public ResultSetMapper(DataSource dataSource, Class<T> clazz) { + this.dataSource = dataSource; + this.clazz = clazz; + + if (clazz != null) { + if (!clazz.isAnnotationPresent(Table.class)) + throw new AnnotationNotFoundException(); + table = clazz.getAnnotation(Table.class); + fields = ClassUtil.getAnnotatedDeclaredFields(clazz, Column.class); + for (Field field : fields) + if (field.getAnnotation(Column.class).isPrimaryKey()) + primaryKeyField.add(field); + /*if (primaryKeyField.isEmpty()) { + primaryKeyFromParent(clazz.getSuperclass()); + fields = ObjectArrays.concat(fields, primaryKeyField.toArray(new Field[0]), Field.class); + }*/ + } + } + + private static void questionMarksParamsCount(String criteria, Object[] params) { + int criteriaCount = criteria == null ? 0 : CharMatcher.is('?').countIn(criteria); + int paramsCount = params != null ? params.length : 0; + if (criteriaCount != paramsCount) + throw new DAOException("?: criteria = " + criteriaCount + "; params = " + paramsCount); + } + + /*private void primaryKeyFromParent(Class<? super T> parent) { + if (parent.equals(Object.class)) // caso base + return; + Field[] parentFields = ClassUtil.getAnnotatedDeclaredFields(parent, Column.class); + for (Field field : parentFields) + if (field.getAnnotation(Column.class).isPrimaryKey()) + primaryKeyField.add(field); + primaryKeyFromParent(parent.getSuperclass()); + }*/ + + @SuppressWarnings({"unchecked"}) + public <T> List<T> findByCriteria(String criteria, Object... params) throws SQLException, IllegalArgumentException, NullPointerException, NumberParseException { + questionMarksParamsCount(criteria, params); + + String sqlStatement = SELECT_SQL + table.name(); + + if (criteria != null) + sqlStatement += WHERE_CLAUSE + criteria.trim(); + + List<T> result = new ArrayList<>(0); + + try (Connection conn = dataSource.getConnection(); + PreparedStatement stmt = conn.prepareStatement(sqlStatement)) { + if (criteria != null) for (int i = 0; i < params.length; i++) stmt.setObject(i + 1, params[i]); + System.out.println(stmt.toString()); // For debug purpose + try (ResultSet rs = stmt.executeQuery()) { + while (rs.next()) { + T item = (T) clazz.newInstance(); + for (Field field : fields) { + Object value; + Class<?> type = field.getType(); + value = type.equals(YearMonth.class) ? YearMonth.parse(rs.getString(field.getAnnotation(Column.class).name()), DateTimeFormatter.ofPattern("yyyy-MM-00")) : rs.getObject(field.getAnnotation(Column.class).name()); + if (type.isPrimitive()) { + Class<?> boxed = Primitives.wrap(type); + value = boxed.cast(value); + } + field.setAccessible(true); + field.set(item, value); + field.setAccessible(false); + } + result.add(item); + } + } + } catch (IllegalAccessException | InstantiationException e) { + e.printStackTrace(); + } + return result; + } + + public String findById() { + if (primaryKeyField.isEmpty()) + throw new NullPointerException("Primary Key is not found"); + else if (primaryKeyField.size() > 1) + throw new UnsupportedOperationException("Only one primary key"); + return primaryKeyField.get(0).getAnnotation(Column.class).name() + " = ?"; + } + + public void deleteById(Long id) throws SQLException, IllegalArgumentException, NullPointerException, NumberParseException { + if (primaryKeyField.isEmpty()) + throw new NullPointerException("Primary Key is not found"); + else if (primaryKeyField.size() > 1) + throw new UnsupportedOperationException("Only one primary key"); + deleteByCriteria(primaryKeyField.get(0).getAnnotation(Column.class).name() + " = ?", id); + } + + public void getByCriteria(String criteria, Object... params) { + questionMarksParamsCount(criteria, params); + } + + public void update(T item) throws SQLException, IllegalArgumentException, NullPointerException, NumberParseException { + if (primaryKeyField.isEmpty()) + throw new NullPointerException("Primary Key is not found"); + StringJoiner joiner = new StringJoiner(" AND "); + Object[] params = criteriaJoiner(item, joiner); + updateByCriteria(item, joiner.toString(), params); + } + + public void updateByCriteria(T item, String criteria, Object... params) throws SQLException, IllegalArgumentException, NullPointerException, NumberParseException { + questionMarksParamsCount(criteria, params); + + StringJoiner joiner = new StringJoiner(DELIMITER); + + List<Field> filteredFields = new ArrayList<>(0); + Column column; + for (Field field : fields) { + field.setAccessible(true); + column = field.getAnnotation(Column.class); + if ((field.getDeclaringClass().equals(clazz) || column.isPrimaryKey()) && !column.hold()) { + joiner.add(field.getAnnotation(Column.class).name() + " = ?"); + filteredFields.add(field); + } + } + + String sqlStatement = UPDATE_SQL + table.name() + SET_CLAUSE + joiner.toString() + + WHERE_CLAUSE + criteria.trim(); + + executeStatement(sqlStatement, item, filteredFields, params); + } + + private void executeStatement(String sqlStatement, T item, List<Field> filteredFields, Object... params) throws SQLException, IllegalArgumentException, NullPointerException, NumberParseException { + try { + boolean keysGeneration = primaryKeyField.stream().allMatch(x -> { + try { + return x.get(item) == null; + } catch (IllegalAccessException e) { + e.printStackTrace(); + return false; + } + }); + try (Connection conn = dataSource.getConnection(); + PreparedStatement stmt = keysGeneration ? conn.prepareStatement(sqlStatement, Statement.RETURN_GENERATED_KEYS) : conn.prepareStatement(sqlStatement)) { + int counter = 1; + for (Field field : filteredFields) { + if (field.getType().equals(YearMonth.class)) { + String date = ((YearMonth) field.get(item)).format(DateTimeFormatter.ofPattern("yyyy-MM-00")); + stmt.setString(counter++, field.getAnnotation(Column.class).isNullable() && "".equals(date) ? null : date); + } else + stmt.setObject(counter++, field.getAnnotation(Column.class).isNullable() && "".equals(field.get(item)) ? null : field.get(item)); + } + for (Object param : params) + stmt.setObject(counter++, param); + + System.out.println(stmt.toString()); // For debug purpose + + int affectedRows = stmt.executeUpdate(); + if (keysGeneration) { + if (affectedRows == 0) + throw new SQLException("No rows affected."); + try (ResultSet generatedKeys = stmt.getGeneratedKeys()) { + if (generatedKeys.next()) + Arrays.stream(fields).filter(p -> p.getAnnotation(Column.class).isPrimaryKey()).findFirst().get().set(item, generatedKeys.getLong(1)); + else + throw new SQLException("No ID obtained."); + } + } + } + } catch (IllegalAccessException e) { + e.printStackTrace(); + } finally { + filteredFields.clear(); + for (Field field : fields) + field.setAccessible(false); + } + } + + public void save(T item, boolean replaceMode, boolean ignore) throws SQLException, IllegalArgumentException, NullPointerException, NumberParseException { + try { + StringJoiner joiner = new StringJoiner(DELIMITER, " ( ", " ) "); + + List<Field> filteredFields = new ArrayList<>(0); + Column column; + for (Field field : fields) { + field.setAccessible(true); + column = field.getAnnotation(Column.class); + if ((field.getDeclaringClass().equals(clazz) || column.isPrimaryKey()) && ((replaceMode || ignore) && column.isPrimaryKey() && field.get(item) != null || !(field.get(item) == null && (column.isPrimaryKey() || column.hasDefaultValue())))) { + joiner.add(field.getAnnotation(Column.class).name()); + filteredFields.add(field); + } + } + + String sqlStatement = INSERT_SQL; + if (ignore) + sqlStatement += IGNORE_SQL; + sqlStatement += INTO_SQL + table.name() + joiner.toString() + VALUES_CLAUSE; + + joiner = new StringJoiner(DELIMITER, " (", ")"); + + for (int i = 0; i < filteredFields.size(); i++) + joiner.add("?"); + + sqlStatement += joiner.toString(); + + if (replaceMode) { + sqlStatement += REPLACE_SQL; + joiner = new StringJoiner(DELIMITER + " "); + for (Field field : filteredFields) { + String nameColumn = field.getAnnotation(Column.class).name(); + joiner.add(nameColumn + "=" + VALUES_CLAUSE + "(" + nameColumn + ")"); + } + sqlStatement += joiner.toString(); + } + executeStatement(sqlStatement, item, filteredFields); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + + private Object[] criteriaJoiner(T item, StringJoiner joiner) { + Object[] params = new Object[0]; + for (Field field : primaryKeyField) { + joiner.add(field.getAnnotation(Column.class).name() + " = ?"); + field.setAccessible(true); + try { + params = ObjectArrays.concat(params, field.get(item)); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } finally { + field.setAccessible(false); + } + } + return params; + } + + public void delete(T item) throws SQLException, IllegalArgumentException, NullPointerException, NumberParseException { + if (primaryKeyField.isEmpty()) + throw new NullPointerException("Primary Key is not found"); + StringJoiner joiner = new StringJoiner(" AND "); + Object[] params = criteriaJoiner(item, joiner); + deleteByCriteria(joiner.toString(), params); + } + + public void deleteByCriteria(String criteria, Object... params) throws SQLException, IllegalArgumentException, NullPointerException, NumberParseException { + questionMarksParamsCount(criteria, params); + + String sqlStatement = DELETE_SQL + FROM_CLAUSE + table.name() + WHERE_CLAUSE + criteria.trim(); + + try (Connection conn = dataSource.getConnection(); + PreparedStatement stmt = conn.prepareStatement(sqlStatement)) { + for (int i = 0; i < params.length; i++) stmt.setObject(i + 1, params[i]); + System.out.println(stmt.toString()); // For debug purpose + stmt.executeUpdate(); + } + } + + public Object customQuery(String query, Object... params) throws SQLException, IllegalArgumentException, NullPointerException, NumberParseException { + questionMarksParamsCount(query, params); + + try (Connection conn = dataSource.getConnection(); + PreparedStatement stmt = conn.prepareStatement(query, Statement.RETURN_GENERATED_KEYS)) { + for (int i = 0; i < params.length; i++) stmt.setObject(i + 1, params[i]); + System.out.println(stmt.toString()); // For debug purpose + if (stmt.execute()) { + try (ResultSet rs = stmt.getResultSet()) { + List<T> items = new ArrayList<>(0); + while (rs.next()) { + T item = clazz.newInstance(); + for (Field field : fields) { + Object value; + Class<?> type = field.getType(); + value = type.equals(YearMonth.class) ? YearMonth.parse(rs.getString(field.getAnnotation(Column.class).name()), DateTimeFormatter.ofPattern("yyyy-MM-00")) : rs.getObject(field.getAnnotation(Column.class).name()); + if (type.isPrimitive()) { + Class<?> boxed = Primitives.wrap(type); + value = boxed.cast(value); + } + field.setAccessible(true); + field.set(item, value); + field.setAccessible(false); + } + items.add(item); + } + return items; + } + } else { + try (ResultSet rs = stmt.getGeneratedKeys()) { + if (rs.next()) + return rs.getLong(1); + } + } + } catch (IllegalAccessException | InstantiationException e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/src/contents/appendices/orm/assets/snippets/Signup.java b/src/contents/appendices/orm/assets/snippets/Signup.java new file mode 100644 index 0000000..faf1077 --- /dev/null +++ b/src/contents/appendices/orm/assets/snippets/Signup.java @@ -0,0 +1,82 @@ +package com.trimaral.servlet.customer; + +import com.trimaral.Roles; +import com.trimaral.dao.LoginDAO; +import com.trimaral.dao.UserRoleDAO; +import com.trimaral.entity.Login; +import com.trimaral.entity.UserRole; +import com.trimaral.utils.PasswordCreator; +import com.trimaral.utils.SMTPMXLookup; +import com.trimaral.utils.VerifyRecaptcha; + +import javax.annotation.Resource; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.sql.DataSource; +import java.io.IOException; + +@WebServlet(name = "Signup", urlPatterns = {"%2Fsignup"}) +public class Signup extends HttpServlet { + + @Resource(name = "jdbc/TrimarDB") + private DataSource dataSource; + private LoginDAO loginDAO; + + @Override + public void init() throws ServletException { + loginDAO = new LoginDAO(dataSource); + } + + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + try { + String email = request.getParameter("email"); + Login login = loginDAO.findByEmail(email); + if (login != null) { + request.getRequestDispatcher("/WEB-INF/pages/customer/signup.jsp?exists=true").forward(request, response); + return; + } + String newPassword = request.getParameter("newPassword"); + String confirmPassword = request.getParameter("confirmPassword"); + if (newPassword.length() < Login.PASSWORD_LENGTH) + throw new IllegalArgumentException("Password too short"); + if (!newPassword.equals(confirmPassword)) + throw new IllegalArgumentException("Passwords don't match"); + if (request.getParameter("termsCheckbox") == null) + throw new IllegalArgumentException("Unchecked Terms & Conditions"); + + // get reCAPTCHA request param + String gRecaptchaResponse = request.getParameter("g-recaptcha-response"); + boolean verify = VerifyRecaptcha.verify(gRecaptchaResponse); + if (!verify) { + response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + return; + } + + if (!SMTPMXLookup.isAddressValid(email)) { + request.getRequestDispatcher("/WEB-INF/pages/customer/signup.jsp?invalid=true").forward(request, response); + return; + } + + login = new Login(); + login.setEmail(email); + login.setPassword(PasswordCreator.getHexPassword(newPassword)); + loginDAO.save(login); + UserRole userRole = new UserRole(); + userRole.setEmail(login.getEmail()); + userRole.setRoleName(String.valueOf(Roles.PRIVATO)); + UserRoleDAO userRoleDAO = new UserRoleDAO(dataSource); + userRoleDAO.save(userRole); + request.getSession().setAttribute("requestEmail", login); + response.sendRedirect(request.getContextPath() + "/confirm-email"); + } catch (Exception e) { + throw new ServletException(e); + } + } + + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + request.getRequestDispatcher("/WEB-INF/pages/customer/signup.jsp").forward(request, response); + } +} -- GitLab