feat: add sorting

This commit is contained in:
Sergey Krylov 2026-03-09 11:46:01 +03:00
parent 73b6f86aab
commit 4a2f819dba
5 changed files with 142 additions and 9 deletions

View File

@ -4,11 +4,42 @@
<head>
<title>Charm Profiles</title>
<%@ include file="style.html" %>
<c:url var="baseUrl" value="${requestScope['javax.servlet.forward.servlet_path']}">
<c:param name="emailStartWith" value="${filter.emailStartWith}"/>
<c:param name="nameStartWith" value="${filter.nameStartWith}"/>
<c:param name="surnameStartWith" value="${filter.surnameStartWith}"/>
<c:param name="status" value="${filter.status}"/>
<c:param name="gteAge" value="${filter.gteAge}"/>
<c:param name="ltAge" value="${filter.ltAge}"/>
<c:param name="sort" value="id"/>
</c:url>
<c:url var="sortUrlWithId" value="${baseUrl}">
<c:param name="sort" value="id"/>
</c:url>
<c:url var="sortUrlWithEmail" value="${baseUrl}">
<c:param name="sort" value="email"/>
</c:url>
<c:url var="sortUrlWithName" value="${baseUrl}">
<c:param name="sort" value="name"/>
</c:url>
<c:url var="sortUrlWithSurname" value="${baseUrl}">
<c:param name="sort" value="surname"/>
</c:url>
<c:url var="sortUrlWithAge" value="${baseUrl}">
<c:param name="sort" value="birth_date"/>
</c:url>
<c:url var="sortUrlWithStatus" value="${baseUrl}">
<c:param name="sort" value="status"/>
</c:url>
<c:url var="sortUrlWithRole" value="${baseUrl}">
<c:param name="sort" value="role"/>
</c:url>
</head>
<body>
<%@ include file="header.jsp" %>
<div>
<form action="/profiles" method="get">
<input type="hidden" name="sort" value="${filter.sort}">
<table>
<tr class="hiddenRow">
<td>
@ -73,12 +104,76 @@
</form>
<table>
<tr>
<td><h3>id</h3></td>
<td><h3>${wordBundle.getWord("email")}</h3></td>
<td><h3>${wordBundle.getWord("name")}</h3></td>
<td><h3>${wordBundle.getWord("surname")}</h3></td>
<td><h3>${wordBundle.getWord("age")}</h3></td>
<td><h3>${wordBundle.getWord("status")}</h3></td>
<td>
<a href="${sortUrlWithId}" class="hiddenLink">
<h3>
id
<c:if test="${filter.sort == 'id' or filter.sort == null}">
^
</c:if>
</h3>
</a>
</td>
<td>
<a href="${sortUrlWithEmail}" class="hiddenLink">
<h3>
${wordBundle.getWord("email")}
<c:if test="${filter.sort == 'email'}">
^
</c:if>
</h3>
</a>
</td>
<td>
<a href="${sortUrlWithName}" class="hiddenLink">
<h3>
${wordBundle.getWord("name")}
<c:if test="${filter.sort == 'name'}">
^
</c:if>
</h3>
</a>
</td>
<td>
<a href="${sortUrlWithSurname}" class="hiddenLink">
<h3>
${wordBundle.getWord("surname")}
<c:if test="${filter.sort == 'surname'}">
^
</c:if>
</h3>
</a>
</td>
<td>
<a href="${sortUrlWithAge}" class="hiddenLink">
<h3>
${wordBundle.getWord("age")}
<c:if test="${filter.sort == 'birth_date'}">
^
</c:if>
</h3>
</a>
</td>
<td>
<a href="${sortUrlWithStatus}" class="hiddenLink">
<h3>
${wordBundle.getWord("status")}
<c:if test="${filter.sort == 'status'}">
^
</c:if>
</h3>
</a>
</td>
<td>
<a href="${sortUrlWithRole}" class="hiddenLink">
<h3>
${wordBundle.getWord("role")}
<c:if test="${filter.sort == 'role'}">
^
</c:if>
</h3>
</a>
</td>
</tr>
<c:forEach var="profile" items="${profiles}">
<tr>
@ -104,9 +199,12 @@
</c:if>
</c:forEach>
</select>
<c:if test="${profile.role != 'ADMIN'}">
<button type="submit">${wordBundle.getWord("save")}</button>
</c:if>
</form>
</td>
<td><h4>${profile.role}</h4></td>
</tr>
</c:forEach>
</table>

View File

@ -27,6 +27,7 @@ public class ProfileDao {
public static final String INSERT = "INSERT INTO profile (email, password) VALUES (?, ?)";
private static final ProfileDao INSTANCE = new ProfileDao();
private Set<String> validColumns;
@SneakyThrows
public static ProfileDao getInstance() {
@ -85,7 +86,7 @@ public class ProfileDao {
.addStatus(filter.getStatus())
.addLTAge(filter.getLtAge())
.addGTEAge(filter.getGteAge())
.build();
.build(getValidSort(filter.getSort()));
try (
Connection connection = ConnectionManager.getConnection();
@ -108,6 +109,30 @@ public class ProfileDao {
}
}
private String getValidSort(String sort) {
if (validColumns == null) {
validColumns = new HashSet<>();
try (Connection conn = getConnection();) {
ResultSet rs = conn.getMetaData().getColumns(null, null, "profile", null);
while(rs.next()) {
String comment = rs.getString("REMARKS");
if("sortable".equals(comment)) {
validColumns.add(rs.getString("COLUMN_NAME"));
}
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
if (validColumns.contains(sort)) {
return sort;
} else {
return "id";
}
}
public void update(Profile profile) {
Query query = new ProfileUpdateQueryBuilder()
.addEmail(profile.getEmail())

View File

@ -14,4 +14,5 @@ public class ProfileFilter {
Integer ltAge;
Integer gteAge;
Status status;
String sort;
}

View File

@ -112,4 +112,9 @@ public class ProfileSelectQueryBuilder {
public Query build() {
return new Query(sb.toString(), args);
}
public Query build(String sort) {
sb.append(" ORDER BY ").append(sort).append(" ASC");
return new Query(sb.toString(), args);
}
}

View File

@ -49,6 +49,10 @@ public class RequestToProfileFilterMapper implements Mapper<HttpServletRequest,
Status status = isBlank(statusArg) ? null : Status.valueOf(statusArg);
filter.setStatus(status);
String sortArg = req.getParameter("sort");
String sort = isBlank(sortArg) ? "id" : sortArg;
filter.setSort(sort);
return filter;
}
}